2013-05-30 46 views
1

我有以下foreach語句:低效的實體框架查詢

foreach (var articleId in cleanArticlesIds) 
{ 
    var countArt = context.TrackingInformations.Where(x => x.ArticleId == articleId).Count(); 
    articleDictionary.Add(articleId, countArt); 
} 

數據庫看起來像這樣

TrackingInformation(Id, ArticleId --some stuff 
Article(Id, --some stuff 

我想要做的是讓所有的物品IDS從TrackingInformations表計數。 例如:

ArticleId:1 Count:1 
ArticleId:2 Count:8 
ArticleId:3 Count:5 
ArticleId:4 Count:0 

,所以我可以有一個dictionary<articleId, count>

上下文是實體框架的DbContext。問題是這個解決方案的工作速度非常慢(數據庫中有大於10K的文章,它們應該快速增長)

+0

你認爲「慢」是什麼?您應該按文章ID對數據進行分組並使用這些結果。 –

回答

2

如果TrackingInformation是第一個導航的財產,那麼你可以這樣做:

var result=context.Article.Select(a=>new {a.id,Count=a.TrackingInformation.Count()}); 

付諸一本字典也很簡單:

var result=context.Article 
    .Select(a=>new {a.id,Count=a.TrackingInformation.Count()}) 
    .ToDictionary(a=>a.id,a=>a.Count); 

如果TrackingInforation ISN」 t導航屬性,那麼你可以這樣做:

var result=context.Article.GroupJoin(
      context.TrackingInformation, 
      foo => foo.id, 
      bar => bar.id, 
      (x,y) => new { id = x.id, Count = y.Count() }) 
     .ToDictionary(a=>a.id,a=>a.Count); 
+0

你不會遇到Select n + 1問題(只有一個數據庫請求),而且你也不需要用這種方式來解決缺失的文章。 –

+0

+1更強大的解決方案 –

+0

謝謝!這對我來說是最好的解決方案。我只需要添加一個其中緊密: VAR結果= context.Articles.GroupJoin( context.TrackingInformations, 技術=> art.Id, 軌道=> track.ArticleId, (X,Y)=>新(x => cleanArticlesIds.Contains(x.id))。ToDictionary(a => a.id,a => a.Count); {id = x.Id,Count = y.Count()}) – 7h4ro3

4

嘗試下一個查詢以收集分組數據,並添加缺少的信息。您可以嘗試跳過Select條款,我不知道EF是否可以良好處理ToDictionary

如果遇到Select n + 1問題(數據庫請求的數額巨大),您可以添加SelectToDictionary之間ToList()步驟,使所有需要的信息將被納入內存。

這取決於您的所有映射配置環境,所以爲了獲得良好的性能,您需要針對不同的查詢進行一些操作。主要方法是在數據庫級別收集儘可能多的數據,但只有很少的查詢。

var articleDictionary = 
    context.TrackingInformations.Where(trackInfo => cleanArticlesIds.Contains(trackInfo.ArticleId)) 
           .GroupBy(trackInfo => trackInfo.ArticleId) 
           .Select(grp => new{grp.Key, Count = grp.Count()}) 
           .ToDictionary(info => "ArticleId:" + info.Key, 
               info => info.Count); 

foreach (var missingArticleId in cleanArticlesIds) 
{ 
    if(!articleDictionary.ContainsKey(missingArticleId)) 
     articleDictionary.add(missingArticleId, 0); 
} 
+0

這不是一個壞的方法,只不過你可能會更適合做一個單一的查詢來檢索跟蹤信息,做第二次LINQ查詢來通過除了聯合它們以及最終轉換成字典來檢索缺失的文章。這會導致兩個數據庫調用,並且完全是LINQ,但仍然不如我給出的答案那樣高效,因爲它只有一個數據庫調用。 –

+0

@RobertMcKee好吧,在我的例子中,我只有1個數據庫調用,添加'missingArticleId'根本不需要任何數據庫調用。 –

+0

我假設cleanArticlesIds是從數據庫中檢索的。 –