Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework Eager Loading Filter

I have a simple query I want to do like this:

1) Products have ChildProducts which have PriceTiers
2) I want to get all the Products that have a Category with a ID of 1 and Display = true.
3) I want to then include all the ChildProducts that have Display = true.
4) And then include the PriceTiers that have IsActive = true.

From what I have read, EF does not support Eager Loading with filters, so the following will not work:

ProductRepository.Query.IncludeCollection(Function(x) x.ChildProducts.Where(Function(y) y.Display).Select(Function(z) z.PriceTiers.Where(Function(q) q.IsActive))).Where(Function(x) x.Categories.Any(Function(y) y.ID = ID)))

Any suggestions?

like image 239
Sam Avatar asked Apr 14 '11 06:04

Sam


People also ask

How do I set eager loading in Entity Framework?

Eager loading is the process whereby a query for one type of entity also loads related entities as part of the query. Eager loading is achieved by use of the Include method. For example, the queries below will load blogs and all the posts related to each blog. Include is an extension method in the System.

What is lazy loading and eager loading in Entity Framework?

Lazy loading in Entity Framework is the default phenomenon that happens for loading and accessing the related entities. However, eager loading is referred to the practice of force-loading all these relations.

What is .include in Entity Framework?

Entity Framework Classic Include The Include method lets you add related entities to the query result. In EF Classic, the Include method no longer returns an IQueryable but instead an IncludeDbQuery that allows you to chain multiple related objects to the query result by using the AlsoInclude and ThenInclude methods.

How do I enable lazy loading in Entity Framework?

Lazy loading means delaying the loading of related data, until you specifically request for it. When using POCO entity types, lazy loading is achieved by creating instances of derived proxy types and then overriding virtual properties to add the loading hook.


1 Answers

Start from the bottom up, meaning, apply filter on the PriceTier object and its parents, and include its parents (C# sorry, but hopefully you get the point):

repository.PriceTiers
  .Include("ChildProduct.Product") // eager load parents
  .Where(priceTier => 
    priceTier.IsActive &&
    priceTier.ChildProduct.Display &&
    priceTier.ChildProduct.Product.ID == 1 &&
    priceTier.ChildProduct.Product.Display)
  .AsEnumerable() // execute SQL statement
  .Select(priceTier => 
    priceTier.ChildProduct.Product) // return products rather than price tiers

(Note: priceTier => in C# is the same as Function(priceTier) in VB.NET)

MergeOption should ideally be set to something other than NoTracking when executing the query. Otherwise, EF will not ensure that an object that appears multiple times in the result set of the query is only materialized once, such as a Product or ChildProduct:

Unwanted results: PriceTier 1 and 2 have the same parents, but the parents have been materialized multiple times - once for each PriceTier.

  • Product 1
    • ChildProduct 1
      • PriceTier 1
  • Product 1
    • ChildProduct 1
      • PriceTier 2

Ideal results: Set MergeOption to anything other than NoTracking to get these results:

  • Product 1
    • ChildProduct 1
      • PriceTier 1
      • PriceTier 2
like image 87
bernhof Avatar answered Oct 26 '22 23:10

bernhof