多对多关联数据最优获取方案:如何关联User等多角色类实现列表需求
解决方案
以下三种优化方案可根据你的技术栈和可修改范围选择:
方案1:给User类补充导航属性(最优,符合ORM设计规范)
直接在User类中补充关联对象的导航属性,结合业务规则封装身份信息快捷访问属性:
class User { // 原有属性省略 public Intern? InternInfo { get; set; } public Employee? EmployeeInfo { get; set; } public ICollection<Plumber>? PlumberPosts { get; set; } public ICollection<Technician>? TechnicianPosts { get; set; } // 快捷属性,直接返回用户身份类型和对应编号 public string IdentityType => InternInfo != null ? "Intern" : "Employee"; public string IdentityNumber => InternInfo?.InternNumber ?? EmployeeInfo?.EmployeeNumber ?? string.Empty; }
之后生成目标列表时可直接访问导航属性,无需额外查询:
// 生成Plumber列表 var plumberList = plumbers.Select(p => new { p.Id, p.PlumberNumber, p.UserId, IdentityType = p.U.IdentityType, IdentityNumber = p.U.IdentityNumber }).ToList(); // Technician列表写法完全一致 var technicianList = technicians.Select(t => new { t.Id, t.TechnicianNumber, t.UserId, IdentityType = t.U.IdentityType, IdentityNumber = t.U.IdentityNumber }).ToList();
方案2:预构建身份字典(无法修改实体类时首选)
如果不能调整实体类结构,可一次性加载所有用户的身份信息生成字典,将遍历过程中的查找复杂度从O(n)降到O(1),避免重复Linq查询:
// 仅查询一次,构建UserId到身份信息的映射字典 var userIdentityDict = interns .Select(i => new { i.UserId, Type = "Intern", Number = i.InternNumber }) .Concat(employees.Select(e => new { e.UserId, Type = "Employee", Number = e.EmployeeNumber })) .ToDictionary(x => x.UserId); // 生成Plumber列表,直接走字典快速查询 var plumberList = plumbers.Select(p => new { p.Id, p.PlumberNumber, p.UserId, IdentityType = userIdentityDict[p.UserId].Type, IdentityNumber = userIdentityDict[p.UserId].Number }).ToList();
方案3:EF Core场景下数据库层面直接投影
如果是用EF Core从数据库查询数据,直接在查询阶段做关联投影,由数据库引擎优化关联逻辑,无需加载全量数据到内存:
var plumberList = await dbContext.Plumbers .Select(p => new { p.Id, p.PlumberNumber, p.UserId, IdentityType = dbContext.Interns.Any(i => i.UserId == p.UserId) ? "Intern" : "Employee", IdentityNumber = dbContext.Interns.Where(i => i.UserId == p.UserId).Select(i => i.InternNumber).FirstOrDefault() ?? dbContext.Employees.Where(e => e.UserId == p.UserId).Select(e => e.EmployeeNumber).FirstOrDefault() }) .ToListAsync();
内容的提问来源于stack exchange,提问作者KaasGierInFrankrijk
相关产品推荐
相关产品推荐

