0

NOTE: This is Entity Framework 7 / Entity Framework Core running on DNX.

I have the following two models:

public class ProductTag
{
    [Key]
    public Guid Id { get; set; }

    [Required]
    public Guid TagId { get; set; }
    public Tag Tag { get; set; }
    [Required]
    public Guid ProductId { get; set; }
    public Product Product { get; set; }
}

public class Product
{
    [Key]
    public Guid Id { get; set; }

    [Required]
    public String Name { get; set; }
    [Required]
    public UInt32 Price { get; set; }

    public List<ProductTag> Tags { get; set; } = new List<ProductTag>();
}

When I try to execute the following query, it fails to find any matches:

await _bagsContext.Products
    .Where(product => expectedTagIds
        .All(expectedTagId => product.Tags
            .Select(productTag => productTag.TagId)
            .Contains(expectedTagId)))
    .ToListAsync();

Note: When I run the following query I get the full results, including the Tags!

await _bagsContext.Products.ToListAsync()

This suggests that it is the Where clause specifically that doesn't have the necessary things populated. Perhaps this is an issue (as suggested in the comments) of the Where clause being executed client side before the DB is queried for the Products.

The goal of the query is to return a list of products that have every expectedTagId on them.

For a simple example take the two products

  • apple - tags: fruit, round
  • banana - tags: fruit, long

Given a call to the above code with expectedTagIds for the tags fruit and round would only return apple.

I managed to fix my issue and get the above query to work by adding the following line above the call.

Task.WaitAll(_bagsContext.ProductTags.LoadAsync(), _bagsContext.Products.LoadAsync());

I kind of understand why ProductTags needs to be pulled in, I assume that LINQ to Entities doesn't drill deep enough into the Where clause to realize that it needs the tags when it compiles the query.

However, I can't fathom why I need to call LoadAsync() on Products. Products is the table I am querying over.

Micah Zoltu
  • 6,764
  • 5
  • 44
  • 72
  • Bonus if someone can show me a better (less code, easier to read) way to do select all products that match all tags. – Micah Zoltu Apr 25 '16 at 07:43
  • Do you try to use .Include() ?? – Thomas Apr 25 '16 at 08:49
  • Are you using RC1? A lot of bugs have been fixed since RC1. I tried it with a nightly build of RC2 from a couple of weeks ago and it runs, but it is still evaluated on the client side. About two weeks ago I read of a couple of situations where EF Core uses client side evaluation. I would live for now with the workaround and look into that when RC2-Final is released. – noox Apr 25 '16 at 20:48
  • I'm using whatever version is the latest pre-release in NuGet as of this past weekend. I can check for specific version when I get home this evening. – Micah Zoltu Apr 25 '16 at 23:41
  • @Thomas I'm not familiar with `.Include()`. I'll research and give it a try this evening. – Micah Zoltu Apr 25 '16 at 23:41
  • `_bagsContext.Products.Include(product => product.Tags)` did not resolve the issue. I am using `7.0.0-rc1-final` – Micah Zoltu Apr 26 '16 at 01:08
  • Things are slightly better (readability wise) with `await _bagsContext.Products.Include(product => product.Tags).LoadAsync())`, though it is still unclear to me why I need to load `Products` at all. – Micah Zoltu Apr 26 '16 at 01:18
  • Any improvment ? Anyway you shouldn't use Guid as a primary key (in fact as a clustered index), this is a bad practice using SQL Server. http://stackoverflow.com/questions/11938044/what-are-the-best-practices-for-using-a-guid-as-a-primary-key-specifically-rega – Thomas Apr 26 '16 at 09:32
  • With RC1 much simpler queries do not work. And I think here a `... AND EXISTS ()` query or something similar has to be built for every ProductTag in the list. So as I said: I'd wait till RC2 is final. If this is too slow you could just take one tag of the list to query the database and check the others on the client side. – noox Apr 26 '16 at 16:21

0 Answers0