Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 低效的实体框架查询_C#_Linq_Entity Framework - Fatal编程技术网

C# 低效的实体框架查询

C# 低效的实体框架查询,c#,linq,entity-framework,C#,Linq,Entity Framework,我有以下声明: foreach (var articleId in cleanArticlesIds) { var countArt = context.TrackingInformations.Where(x => x.ArticleId == articleId).Count(); articleDictionary.Add(articleId, countArt); } 数据库看起来像这样 TrackingInformation(Id, ArticleId --so

我有以下声明:

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
所以我可以有一本字典


Context是实体框架DbContext。问题是此解决方案的运行速度非常慢,数据库中的文章数量超过了10k篇,它们应该会快速增长

尝试下一次查询以收集分组数据,并添加缺少的信息。你们可以试着跳过Select子句,我不知道EF是否能很好地处理TODICTIONAL

如果遇到大量数据库请求的问题,可以在Select和ToDictionary之间添加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);
}

尝试下一次查询以收集分组数据,并添加缺少的信息。你们可以试着跳过Select子句,我不知道EF是否能很好地处理TODICTIONAL

如果遇到大量数据库请求的问题,可以在Select和ToDictionary之间添加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);
}

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

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

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

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


你对“慢”的定义是什么?您应该按articleID对数据进行分组并使用这些结果。您将什么定义为“慢”?您应该按articleID对数据进行分组并使用这些结果。您不会遇到选择n+1问题,只需要一个数据库请求,也不需要以这种方式说明缺少的文章。谢谢!这对我来说是最好的解决办法。我只需要添加一个close:var result=context.Articles.GroupJoin context.TrackingInformations,art=>art.Id,track=>track.ArticleId,x,y=>new{Id=x.Id,Count=y.Count}其中x=>cleanArticlesIds.Containsx.id.ToDictionarya=>a.id,a=>a.Count;是的,我和ilya在下面讨论了这个问题。你不会遇到选择n+1的问题,只有一个数据库请求,你也不需要这样解释丢失的文章。谢谢!这对我来说是最好的解决办法。我只需要添加一个close:var result=context.Articles.GroupJoin context.TrackingInformations,art=>art.Id,track=>track.ArticleId,x,y=>new{Id=x.Id,Count=y.Count}其中x=>cleanArticlesIds.Containsx.id.ToDictionarya=>a.id,a=>a.Count;是的,我和ilya在下面讨论了这一点。这不是一个坏方法,只是你最好做一个查询来检索跟踪信息,做第二个LINQ查询来检索缺少的文章,通过except,合并它们,最后转换成字典。这将导致两个数据库调用,完全是LINQ,但仍然没有我上面给出的答案(只有一个数据库调用)那么有效。@RobertMcKee在我的示例中,我只有一个数据库调用,添加missingArticleId根本不需要任何数据库调用。我假设CleanArticleSID是从数据库中检索的。@RobertMcKee Ask OP,不是我。若你们注意的话,他已经在第一行的代码中使用了它。我不知道他是不是从数据库里查到的。为什么不从用户界面?为什么不从另一个服务电话?我只是不知道,我想做尽可能少的假设,专注于一项特定的任务,尽可能接近作者的编码风格。这很公平,但如果你想假设CleanArticleSID没有从数据库中检索到,或者可能不是,或者可能不是所有的文章,然后,您应该在其中添加一个where,将从TrackingInformation提取的结果限制为CleanArticleID中的ArticleID,否则您将返回不在其列表中的文章。诚然,我也没有这样做,但我假设他想要一份所有文章的完整列表
t您可能最好只执行一次查询来检索跟踪信息,执行第二次LINQ查询来通过except检索缺少的文章,合并它们,最后转换为字典。这将导致两个数据库调用,完全是LINQ,但仍然没有我上面给出的答案(只有一个数据库调用)那么有效。@RobertMcKee在我的示例中,我只有一个数据库调用,添加missingArticleId根本不需要任何数据库调用。我假设CleanArticleSID是从数据库中检索的。@RobertMcKee Ask OP,不是我。若你们注意的话,他已经在第一行的代码中使用了它。我不知道他是不是从数据库里查到的。为什么不从用户界面?为什么不从另一个服务电话?我只是不知道,我想做尽可能少的假设,专注于一项特定的任务,尽可能接近作者的编码风格。这很公平,但如果你想假设CleanArticleSID没有从数据库中检索到,或者可能不是,或者可能不是所有的文章,然后,您应该在其中添加一个where,将从TrackingInformation提取的结果限制为CleanArticleID中的ArticleID,否则您将返回不在其列表中的文章。当然,我也没有这样做,但我认为他想要一份所有文章的完整列表。