You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core 2.x中使用Include仍出现N+1查询问题求助

EF Core 2.x中Include关联仍出现N+1查询的原因

问题背景

我们拥有Blogs和Comments两张表,Blogs与Comments为一对多关系。现有一个接收博客ID列表作为参数的方法,需返回博客基础信息及其关联评论。最初实现时已使用Include关联Comments,但EF Core 2.x仍生成N+1查询。当前环境为.NET 4.7.x,因使用WCF服务无法升级版本,最终采用了一种不够高效但可用的替代实现,现需明确原代码出现N+1问题的原因。

最初实现代码

public List<BlogDto> GetAllBlogs(List<long> blogIds)
{
    var query = from blogId in blogIds
                join blog in dbContext.Blogs.Include(blog => blog.Comments) on blogId equals blog.Id
                select new BlogDto()
                {
                    Id = blog.Id,
                    Name = blog.Name,
                    // ... 其他属性
                    // Comments prop is List<CommentDto>
                    Comments = blog.Comments.Select(comment => new CommentDto
                                                               {
                                                                   Id = comment.Id,
                                                                   Content = comment.Content 
                                                               }).ToList()

                };

     return query.ToList();
}

原代码出现N+1查询的原因

  • Include被投影操作忽略:EF Core 2.x的Include方法仅作用于将关联数据加载到原始实体对象中,而你在查询中直接通过select new BlogDto()进行投影映射,此时EF Core会忽略Include指令——它认为你不需要加载完整的Blog实体(包括关联的Comments),只需要投影指定的属性,因此不会主动将Comments关联数据一次性查询出来。
  • 投影内的ToList()触发单条查询:在DTO的Comments属性赋值时,你调用了blog.Comments.Select(...).ToList(),这会导致EF Core在获取每个Blog实体后,单独发送一条SQL查询去获取该Blog对应的Comments数据。最终形成1条查询获取所有Blog,加上N条查询分别获取每个Blog的评论,也就是N+1查询。

替代实现代码

public List<BlogDto> GetAllBlogs(List<long> blogIds)
{
    var blogQuery = from blogId in blogIds
                    join blog in dbContext.Blogs on blogId equals blog.Id
                    select new BlogDto()
                    {
                        Id = blog.Id,
                        Name = blog.Name,
                        // ... 其他属性
                    };

    var comments = (from blog in blogQuery
                    join comment in dbContext.Comments on blog.Id equals comment.BlogId
                    select new CommentDto
                    {
                        Id = comment.Id,
                        Content = comment.Content,
                        BlogId = blog.Id
                    }).GroupBy(c => c.BlogId).ToDictionary(v => v.Key, v => v.ToList());

    var blogList = blogQuery.ToList();
    blogList.ForEach(b =>
    {
        if (comments.ContainsKey(b.Id))
        {
            b.Comments = comments[b.Id];
        }
    });

    return blogList;
}

内容的提问来源于stack exchange,提问作者abdismoz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 01:45:30