Entity Framework Core复合表(复合键)查询结构问题求助
看起来你是想通过关联表ProjectSubProject查询出每个Project对应的所有SubProject集合,但当前的查询逻辑导致分组结果里的元素是GetAllProjectsViewModel而不是SubProject,我来帮你梳理下问题和解决方案:
问题原因分析
你当前的查询顺序是:先把每个ProjectSubProject映射为GetAllProjectsViewModel(每个ViewModel包含一个Project和一个SubProject),再按Project分组。这就导致分组后的每个元素都是GetAllProjectsViewModel,所以最终得到的是IGrouping<Project, GetAllProjectsViewModel>,而不是你期望的按Project分组、元素为SubProject的结构。
解决方案
方案1:直接获取IDictionary<Project, List<SubProject>>
如果你的目标是得到以Project为键、对应SubProject列表为值的字典,可以调整查询顺序,先分组再提取子项目集合:
return _context.ProjectSubProjects .Include(ps => ps.Project) .Include(ps => ps.SubProject) .GroupBy(ps => ps.Project) .Select(g => new { Project = g.Key, SubProjects = g.Select(ps => ps.SubProject).ToList() }) .ToDictionary(x => x.Project, x => x.SubProjects);
方案2:获取IGrouping<Project, SubProject>结构
如果你更倾向于IGrouping类型,不需要提前转换为字典,可以直接分组后在使用时提取子项目:
var groupedProjects = _context.ProjectSubProjects .Include(ps => ps.Project) .Include(ps => ps.SubProject) .GroupBy(ps => ps.Project); // 使用时遍历分组 foreach (var projectGroup in groupedProjects) { Project currentProject = projectGroup.Key; IEnumerable<SubProject> subProjects = projectGroup.Select(ps => ps.SubProject); // 后续业务逻辑处理 }
方案3:自定义包含子项目的ViewModel
如果需要返回一个结构化的ViewModel(比如前端需要的格式),可以创建一个专门的ViewModel类,再投影分组结果:
// 先定义ViewModel public class ProjectWithSubProjectsViewModel { public Project Project { get; set; } public IEnumerable<SubProject> SubProjects { get; set; } } // 查询代码 return _context.ProjectSubProjects .Include(ps => ps.Project) .Include(ps => ps.SubProject) .GroupBy(ps => ps.Project) .Select(g => new ProjectWithSubProjectsViewModel { Project = g.Key, SubProjects = g.Select(ps => ps.SubProject) }) .ToList();
额外提示
EF Core中如果你的实体类没有配置双向导航(比如Project类中没有ICollection<ProjectSubProject>),使用关联表查询是合理的。如果后续业务经常需要这种关联查询,可以考虑给Project添加导航属性:
public class Project { public int Id { get; set; } public string ProjectName { get; set; } // 添加导航属性 public ICollection<ProjectSubProject> ProjectSubProjects { get; set; } = new List<ProjectSubProject>(); }
这样后续查询可以更简洁:
return _context.Projects .Include(p => p.ProjectSubProjects) .ThenInclude(ps => ps.SubProject) .Select(p => new ProjectWithSubProjectsViewModel { Project = p, SubProjects = p.ProjectSubProjects.Select(ps => ps.SubProject) }) .ToList();
内容的提问来源于stack exchange,提问作者Nikita Goncharuk

