EF Core执行Union后mapper映射报无法转换集合子查询错误如何解决
报错原因
EF Core执行Union操作时,会合并两个子查询的结果集,合并过程中丢失了Organization实体用于追踪的主键等必要键列信息,而AutoMapper的ProjectTo需要依赖这些键列完成服务端投影转换,因此触发报错。单独查询时没有结果集合并步骤,键列信息完整,可正常执行。
解决方案
方案1:合并查询条件,避免使用Union(最优)
你的需求本质是查询满足「Framework条件 或 隐私政策数据覆盖条件」的Organization,直接将两个判断条件合并到同一个Where中即可,无需使用Union:
var orgResult = context.Applications .Where(c => // 原frameworkOrg查询条件 c.Certifications.Select(f => f.Framework).Any(fr => fr.Name == search.Framework) // 原coveredDataOrg查询条件 || c.PrivacyPolicies.Any(pp => pp.Type == search.DataCovered) ) .Select(apporg => apporg.Organization) .Distinct(); // 作用和Union一致,对重复的Organization去重 var organizationModel = mapper.ProjectTo<Models.Organization>(orgResult).ToList();
该方案仅需执行一次数据库查询,性能最优,也规避了Union带来的列对齐问题。
方案2:先对子查询单独投影,再执行Union
如果需要保留两个独立查询的逻辑,可以先对每个子查询执行ProjectTo转换为DTO后再做Union,DTO不需要EF追踪所需的键列,不会触发报错:
var frameworkOrg = context.Applications .Where(c => c.Certifications.Select(f => f.Framework).Any(fr => fr.Name == search.Framework)) .Select(apporg => apporg.Organization) .ProjectTo<Models.Organization>(); var coveredDataOrg = context.Applications .Where(c => c.PrivacyPolicies.Any(pp => pp.Type == search.DataCovered)) .Select(apporg => apporg.Organization) .ProjectTo<Models.Organization>(); var organizationModel = frameworkOrg.Union(coveredDataOrg).ToList();
如果出现服务端Union执行失败的情况,可以分别给两个子查询加上AsEnumerable(),将结果加载到内存后再执行Union。
方案3:先加载实体到内存再映射
如果上述方案都不适用,可以先把Union后的实体结果加载到内存,再执行内存映射,缺点是会加载Organization的全量字段,性能略低:
var orgResult = frameworkOrg.Union(coveredDataOrg).ToList(); var organizationModel = mapper.Map<List<Models.Organization>>(orgResult);
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

