2012-11-26 20 views
1

我有EF,数据库第一。我有三个模型类:A,BC。 模型ABB具有m2m关系,与C具有m2m关系。奇怪的EF行为 - 意外的长时间

我在此列出A的子集以及相关的BC

在测试环境中,子集中有大约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(); 
} 

花了约164ms - 相当长。

所以我想优化它。

如您所见,第一行IQueryable<A>更改为List<A>。 在这一刻,我认为,查询被执行。

当我想得到BsACB,我认为,执行其他查询。

然后我搜索并找到了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(); 
} 

在我看来,执行应该花费大约10ms,但现在花费550ms。

当我刚刚挂牌As有关的BsCs它需要约10ms。

我在做什么错?

编辑:对不起,C有FK到B.但我不认为它会改变任何东西。

+2

你真的应该调查发射的sql的任何意外的查询。 –

回答

0

如果你的DbContext支持懒加载“这是默认为true”,这将产生许多命中数据库,只要你拨打objA.Bs.ToList()b => b.FirstOrDefault(c => ...)那是因为你没有包含在第一listA查询这些导航性能。

反正尽量使用include方法

var listA = new Entities(...).As.Include("Bs").Include("Bs.Cs").Where(...).ToList(); 
+0

在我的第二种方法中,我包括了“Bs”和“Bs.Cs”('Include(“Bs”).include(“Bs.Cs”)'和'Include(“Bs.Cs”)'甚至比以前更慢。 – Ari

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(); 
       } 

      } 
+0

它不会为每个A元素创建一个数据库查询吗? – Ari

+0

如果一些Bs是相同的不同的话那么否,否则是的。在我的测试中,它似乎比包含快20%,但我没有正式的测试结果。 – fofik