SqlQuery
提出了一些我尚未意识到的问题。
不包括
你正确地解释了原因Include
转换后没有任何效果IEnumerable
to an IQueryable
. Include
扩展一个表达式,并且IEnumerable
没有表达式(并且在将其转换为IQueryable
).
没有附加就没有延迟加载
所以你最终会得到一个列表Product
s 不依附于上下文并且无法延迟加载。您必须附上Product
显式地关联到上下文(例如,通过将其状态设置为Unchanged
)使它们延迟加载。
这是我刚刚发现的事情,这很奇怪。这些实体被具体化为代理对象,但是与通过获取的分离实体相反DbSet.AsNoTracking()
,它们不显示延迟加载。我认为这是一个错误,我报告了它。
但延迟加载会导致 n + 1 查询反模式:分别为每个产品获取 Inventory 对象的查询。所以这不是获取对象图的最佳方法。
没有修复关系
因此,您真正想要的是一次性加载属于这些产品的所有 Inventory 对象,然后让关系修复完成其工作(即 EF 自动填充所有Product.Inventories
集合):
context.Inventories.Where(i => productIds.Contains(i.ProductId)).Load();
...在哪里productIds
是产品 ID 的列表p
.
但关系修复仅适用于附加实体,因此,您必须将它们的状态更改为Unchanged
明确地。如果你这样做了,你就准备好了......但你还没有。
同样,与获取的分离实体存在差异DbSet.AsNoTracking()
。后者对关系修复做出反应,来自SqlQuery
don't!
(相当)复杂的解决方案
那么剩下的就是:加载相关的Inventory
对象如上所示并填充Product.Inventories
自己收藏:
var query = from product in p
join inv context.Inventories.Local
on product.ProductId equals inv.ProductId
into inventories
select new { product, inventories }
foreach(var anon in query)
{
anon.product.Inventories = anon.inventories.ToList();
}
当然,这一切都不太令人满意。