Фильтр нетерпеливой загрузки Entity Framework

#entity-framework #eager-loading

#entity-framework #нетерпеливая загрузка

Вопрос:

У меня есть простой запрос, который я хочу выполнить следующим образом:

1) Products иметь ChildProducts , которые имеют PriceTiers
2) Я хочу получить все, Products которые имеют a Category с a ID равным 1 и Display = true.
3) Затем я хочу включить все, ChildProducts которые имеют Display значение = true.
4) И затем включите те, PriceTiers которые имеют IsActive значение = true.

Из того, что я прочитал, EF не поддерживает быструю загрузку с фильтрами, поэтому следующее не будет работать:

 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)))
  

Есть предложения?

Комментарии:

1. почему вы начинаете задавать несколько вопросов по одной и той же проблеме? Более того, почему вы делаете это снова и снова?

Ответ №1:

Начните снизу вверх, то есть примените фильтр к PriceTier объекту и его родителям и включите его родителей (C # извините, но, надеюсь, вы поняли суть):

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

(Примечание: priceTier => в C # это то же самое, что Function(priceTier) в VB.NET )

MergeOption в идеале должно быть установлено что-то иное, чем NoTracking при выполнении запроса. В противном случае EF не гарантирует, что объект, который появляется несколько раз в результирующем наборе запроса, материализуется только один раз, например, Product или ChildProduct :

Нежелательные результаты: у PriceTier 1 и 2 одни и те же родители, но родители были материализованы несколько раз — по одному разу для каждого PriceTier.

  • Продукт 1
    • Дочерний продукт 1
      • Цена выше 1
  • Продукт 1
    • Дочерний продукт 1
      • Цена выше 2

Идеальные результаты: Установите MergeOption что угодно, кроме NoTracking получения этих результатов:

  • Продукт 1
    • Дочерний продукт 1
      • Цена выше 1
      • Цена выше 2

Комментарии:

1. запуск снизу вверх будет иметь побочный эффект, заключающийся в том, что если существуют родители, у которых нет дочерних элементов, соответствующих фильтрам, эти родители не будут в результирующем наборе. вы могли бы использовать левое соединение для достижения вашей фильтрации

2. Более 5 лет спустя это все еще проблема с EF, и ваш ответ по-прежнему является лучшим решением. Спасибо!

Ответ №2:

вот решение, которое приведет ваши «строки» в соответствие с вашим запросом, используя левые соединения вместо быстрой загрузки и включая родительские строки, в которых не существует дочерних строк для фильтров

 var query = from product in Products
                join child_ in ChildProducts on product equals child_.Product into child_join
                from child in child_join.DefaultIfEmpty()
                join tier_ in PriceTiers on child equals tier_.ChildProduct into tier_join
                from tier in tier_join.DefaultIfEmpty()
                where product.Display amp;amp; product.Category.ID == 1
                where child == null || child.Display
                where tier == null || tier.IsActive
                select new {product, child, tier};