#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
- Дочерний продукт 1
- Цена выше 2
- Дочерний продукт 1
Идеальные результаты: Установите MergeOption
что угодно, кроме NoTracking
получения этих результатов:
- Продукт 1
- Дочерний продукт 1
- Цена выше 1
- Цена выше 2
- Дочерний продукт 1
Комментарии:
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};