低效的实体框架查询

时间:2013-05-30 17:49:31

标签: c# linq entity-framework

我有一个以下的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

我想要做的是从TrackingInformations表中获取所有文章ID。 例如:

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

所以我可以拥有dictionary<articleId, count>

Context是Entity Framework DbContext。问题是这个解决方案工作得非常慢(db中有大约10k篇文章,它们应该快速增长)

2 个答案:

答案 0 :(得分:4)

尝试下一个查询以收集分组数据,并添加缺少的信息。您可以尝试跳过Select子句,我不知道EF是否能够以良好的方式处理ToDictionary

如果遇到Select n + 1问题(大量数据库请求),您可以在ToList()Select之间添加ToDictionary步骤,以便提供所有必需的信息进入记忆。

这取决于您的所有映射配置,环境,因此为了获得良好的性能,您需要使用不同的查询进行一些操作。主要方法是在数据库级别尽可能多地聚合尽可能多的数据。

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

答案 1 :(得分:2)

如果TrackingInformation是Article的可导航属性,则可以执行以下操作:

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不是可导航属性,则可以执行以下操作:

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