EF Core如何在数据库查询前将匿名对象扁平化为IQueryable<RightsEntity>
EF Core 单库调用实现多表RightsEntity查询与扁平化
方案1:从匿名类型IQueryable扁平化
假设你当前已通过关联查询得到包含5个RightsEntity属性的匿名类型IQueryable:
var anonymousQuery = db.People .Join(db.Groups, p => p.GroupId, g => g.Id, (p, g) => new { p, g }) .Join(db.Contracts, pg => pg.p.ContractId, c => c.Id, (pg, c) => new { pg.p, pg.g, c }) // 继续关联ActivityTypes、Vehicles,最终投影到匿名类型 .Select(data => new { PersonRight = new RightsEntity { /* 从data.p映射属性 */ }, GroupRight = new RightsEntity { /* 从data.g映射属性 */ }, ContractRight = new RightsEntity { /* 从data.c映射属性 */ }, ActivityTypeRight = new RightsEntity { /* 从data.at映射属性 */ }, VehicleRight = new RightsEntity { /* 从data.v映射属性 */ } });
要在数据库层面完成扁平化,使用SelectMany将每个匿名对象的5个实体转为序列,EF Core会自动翻译为UNION ALL语句,实现单库调用:
IQueryable<RightsEntity> flattenedQuery = anonymousQuery.SelectMany(anonObj => new[] { anonObj.PersonRight, anonObj.GroupRight, anonObj.ContractRight, anonObj.ActivityTypeRight, anonObj.VehicleRight }); // 若存在可能的null实体,可添加过滤 flattenedQuery = flattenedQuery.Where(right => right != null);
方案2:独立查询后合并(更简洁)
如果五个表的查询无需关联,直接创建每个表对应的RightsEntity投影查询,再用Concat合并,同样生成单库调用的UNION ALL SQL:
var personRights = db.People.Select(p => new RightsEntity { // 映射People表字段到RightsEntity属性 }); var groupRights = db.Groups.Select(g => new RightsEntity { // 映射Groups表字段到RightsEntity属性 }); var contractRights = db.Contracts.Select(c => new RightsEntity { // 映射Contracts表字段到RightsEntity属性 }); var activityTypeRights = db.ActivityTypes.Select(at => new RightsEntity { // 映射ActivityTypes表字段到RightsEntity属性 }); var vehicleRights = db.Vehicles.Select(v => new RightsEntity { // 映射Vehicles表字段到RightsEntity属性 }); IQueryable<RightsEntity> combinedQuery = personRights .Concat(groupRights) .Concat(contractRights) .Concat(activityTypeRights) .Concat(vehicleRights);
关键注意事项
- 确保属性映射逻辑可被EF Core翻译为SQL:避免使用客户端自定义方法,直接在投影中写属性赋值,或使用可翻译的表达式树。
- 两种方案均会在数据库层面完成数据合并,不会提前将匿名类型或中间结果加载到内存,符合性能需求。
- 若需去重,可将
Concat替换为Union(但会增加数据库层面的去重开销)。
内容的提问来源于stack exchange,提问作者kmacek
相关产品推荐
相关产品推荐

