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

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

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

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

上下文是实体框架 DbContext。问题是这个解决方案运行速度非常慢(数据库中有 > 10k 篇文章,它们应该会迅速增长)

4

2 回答 2

4

尝试下一个查询来收集分组数据,然后他们会添加缺失的信息。你可以尝试跳过Select子句,我不知道EF是否可以ToDictionary很好地处理。

如果遇到Select n + 1问题(数据库请求量很大),可以在andToList()之间添加 step ,这样所有需要的信息都会被带入内存。SelectToDictionary

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

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);
}
于 2013-05-30T17:55:08.590 回答
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);
于 2013-05-30T18:00:46.250 回答