EF Core中LINQ关联三表查询返回带嵌套列表DTO的实现方法
问题解决方法
你当前使用连续Inner Join的写法会导致单条组织记录按关联部门数拆成多行重复结果,无法直接在投影中填充子列表,需要调整查询结构使用GroupJoin处理一对多关联,EF Core会将整个查询翻译成单条SQL执行,不会产生N+1查询问题。
推荐写法(无导航属性版本,适配你当前的表结构设计)
不需要额外配置实体导航属性,直接修改查询逻辑即可,TODO位置替换为对应子集合投影,完整代码如下:
var organizationInfo = (from org in _dbContext.Organizations where org.Id.ToUpper() == id.ToUpper() orderby org.CreatedOn ascending // 分组关联组织-部门中间表 join orgDept in _dbContext.OrganizationDepartments on org.Id equals orgDept.OrganizationId into orgDeptList select new OrganizationDto { Id = org.Id, OrganizationName = org.OrganizationName, Logo = org.Logo, IsActive = org.IsActive, // TODO位置的赋值逻辑 OrganizationDepartments = orgDeptList .Join( _dbContext.Departments, od => od.DepartmentId, dept => dept.Id, (od, dept) => new OrganizationDepartmentDto { OrganizationId = org.Id, OrganizationName = org.OrganizationName, DepartmentId = dept.Id, DepartmentName = dept.DepartmentName } ).ToList() }) // 按ID查询单条记录,必须加这个方法取单个实例 .FirstOrDefault();
简化写法(已配置实体导航属性时使用)
如果你的EF实体已经配置了Organization->OrganizationDepartments->Department的级联导航关系,可以用Include+投影的写法,代码更简洁:
var organizationInfo = _dbContext.Organizations .Include(o => o.OrganizationDepartments) .ThenInclude(od => od.Department) .Where(o => o.Id.ToUpper() == id.ToUpper()) .OrderBy(o => o.CreatedOn) .Select(o => new OrganizationDto { Id = o.Id, OrganizationName = o.OrganizationName, Logo = o.Logo, IsActive = o.IsActive, OrganizationDepartments = o.OrganizationDepartments .Select(od => new OrganizationDepartmentDto { OrganizationId = o.Id, OrganizationName = o.OrganizationName, DepartmentId = od.Department.Id, DepartmentName = od.Department.DepartmentName }).ToList() }) .FirstOrDefault();
注意事项
- 上述两种写法都会被EF Core翻译成单条SQL执行,不会产生重复的组织主记录,也不会触发多次数据库查询
- 如果你需要过滤掉没有关联任何部门的组织,可以在投影前加
Where(org => orgDeptList.Any())条件即可 - 数据库如果使用大小写不敏感的排序规则(大部分业务系统默认配置),可以去掉
Id.ToUpper()的转换,进一步利用索引提升查询效率
内容的提问来源于stack exchange,提问作者mnu-nasir
相关产品推荐
相关产品推荐

