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

EF6中如何在Include查询中获取关联项目的最新版本

解决EF6中获取站点及对应最新版本项目的N+1查询问题

问题背景

现有两张数据表:

  • Site表:
IDName
1site1
2Site2
  • Project表:ID与Version为联合主键
IDVersionProjectNameSiteId
11Test11
12Test21

需求是获取所有站点,以及每个站点对应的最新版本项目。原方案通过循环站点逐一查询项目,导致多次数据库往返、性能低下,且尝试的分组降序写法EF6无法转换为SQL语句。

优化方案

方案1:子查询筛选最新版本(EF6原生兼容)

先通过子查询获取每个Project.ID对应的最大版本号,再关联查询完整项目数据,最后与Site表关联,仅需一次数据库往返:

// 子查询:获取每个项目ID的最大版本
var latestProjectVersions = context.Projects
    .GroupBy(p => p.ID)
    .Select(g => new { ProjectId = g.Key, MaxVersion = g.Max(p => p.Version) });

// 关联站点与对应最新版本项目
var sitesWithLatestProjects = await context.Sites
    .AsNoTracking()
    .Include(s => s.UserRelations)
    .Select(s => new 
    {
        Site = s,
        LatestProjects = context.Projects
            .AsNoTracking()
            .Join(latestProjectVersions, 
                p => new { p.ID, p.Version }, 
                lp => new { ProjectId = lp.ProjectId, MaxVersion = lp.MaxVersion },
                (p, lp) => p)
            .Where(p => p.SiteId == s.ID)
            .ToList()
    })
    .ToListAsync();

// 映射回原实体结构
var result = sitesWithLatestProjects.Select(item => 
{
    item.Site.Projects = item.LatestProjects;
    return item.Site;
}).ToList();

return result;

方案2:窗口函数实现(需数据库支持)

如果你的数据库支持窗口函数(如SQL Server 2008+),可以用ROW_NUMBER()为每个项目的版本排序,直接取序号为1的最新版本,查询效率更高:

// 筛选每个项目的最新版本
var latestProjects = context.Projects
    .AsNoTracking()
    .Select(p => new 
    {
        p.ID,
        p.Version,
        p.ProjectName,
        p.SiteId,
        RowNum = SqlFunctions.RowNumber()
            .Over(PartitionBy: p.ID, OrderBy: "Version DESC")
    })
    .Where(p => p.RowNum == 1);

// 关联站点与最新项目
var sitesWithLatestProjects = await context.Sites
    .AsNoTracking()
    .Include(s => s.UserRelations)
    .Select(s => new 
    {
        Site = s,
        LatestProjects = latestProjects.Where(p => p.SiteId == s.ID)
            .Select(p => new Project 
            {
                ID = p.ID,
                Version = p.Version,
                ProjectName = p.ProjectName,
                SiteId = p.SiteId
            })
            .ToList()
    })
    .ToListAsync();

// 映射回原实体
var result = sitesWithLatestProjects.Select(item => 
{
    item.Site.Projects = item.LatestProjects;
    return item.Site;
}).ToList();

return result;

说明

  • 方案1基于EF6原生Linq支持,无需依赖数据库特定函数,兼容性更强;
  • 方案2利用数据库窗口函数,查询性能更优,但需要数据库支持ROW_NUMBER();
  • 两种方案均仅需一次数据库查询,彻底解决原方案的N+1性能问题;
  • 若Site与Project已配置好导航属性(Site包含ICollection<Project> Projects,Project包含Site Site),可简化关联逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 06:01:36