2012-11-26 56 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