我首先拥有EF,数据库。我有三个模型类:A
,B
和C
。
模型A
与B
的m2m关系,B
与C
的m2m关系。
我列出了A
的相关B
和C
的子集。
在测试环境中,子集中有大约20个模型A
,只有少数具有任何相关B
,如果有,则在大多数情况下只有一个。
模型B
始终只有一个相关的C
。我不想更改它,因为将来会有更多与C
相关的B
。
我的第一个方法是:
var listA = new Entities(...).As.Where(...).ToList();
foreach (var objA in listA){
var listC = objA.Bs.ToList().Select(b => b.FirstOrDefault(c => ...)).ToList();
}
花了大约164毫秒 - 很长时间。
所以我想要优化它。
如您所见,第一行IQueryable<A>
更改为List<A>
。
在这一刻,我认为,查询已经执行。
当我想Bs
获取A
而C
获得B
时,我认为会执行另一个查询。
然后我搜索并找到Include
方法。在第二个approuch我使用它像:
var listA = new Entities(...).As.Include("Bs.Cs").Where(...).ToList();
foreach (var objA in listA){
var listC = objA.Bs.ToList().Select(b => b.FirstOrDefault(c => ...)).ToList();
}
在我看来,执行应该需要大约10毫秒,但现在需要550毫秒。
当我只列出与As
和Bs
相关的Cs
时,它需要大约10毫秒。
我做错了什么?
编辑:对不起,C有FK到B.但我认为它没有改变任何东西。
答案 0 :(得分:0)
如果您的DbContext支持延迟加载“默认情况下为true”,只要您调用objA.Bs.ToList()
和b => b.FirstOrDefault(c => ...)
,就会产生很多针对数据库的命中,因为您没有包含这些导航属性在您的第一个listA
查询中。
无论如何都要尝试使用Include方法
var listA = new Entities(...).As.Include("Bs").Include("Bs.Cs").Where(...).ToList();
答案 1 :(得分:0)
根据我的经验,显式加载相关对象的速度要快一些。请尝试使用对象Load()方法加载并使用IsLoaded检查它是否已加载。另外,关闭延迟加载并明确打开连接可能有所帮助。
以下内容可能有所帮助。
var listA = from o in context where (...) select o;
foreach (var i in listA)
{
if (!i.Bs.IsLoaded)
i.Bs.Load();
if (i.Bs != null)
{
if (!i.Bs.Cs.IsLoaded)
i.Bs.Cs.Load();
}
}