Entity Framework中Union合并两表时的LINQ IQueryable类型转换问题
问题
我使用采用代码优先映射的Entity Framework(EF)将数据拉取到Angular UI,现在想通过Union操作从Table1和Table2两个表中获取数据。
原有单表查询代码如下:
var utility = new QueryableUtility<Table1Entity>(); var queryable = utility.findQueryable( Request, db.Table1.AsQueryable(), QueryParamArray.Instance.FSParameterArray, new Table1Entity() );
我修改代码以获取两表公共字段并使用UNION,修改后代码如下:
var t1 = db .Table1 .Select(x => new Table1Dto { Id = x.Id, Name = x.Name, Status = x.Status }).ToList(); var t2 = db .Table2 .Select(x => new Table2Dto { Id = x.Id, Name = x.Name, Status = x.Status }).ToList(); var qry = t1.Union(t2); var utility = new QueryableUtility<Table1Entity>(); var queryable = utility.findQueryable( Request, qry.AsQueryable(), QueryParamArray.Instance.FSParameterArray, new Table1Entity() );
执行时在qry.AsQueryable()行报错:
无法从system.linq.IQueryable<>转换为system.linq.IQueryable<>
解决方案
错误核心是类型不匹配:
t1是List<Table1Dto>类型,t2是List<Table2Dto>类型,即便字段完全一致,二者也是不同类型,Union后的结果无法直接适配QueryableUtility<Table1Entity>要求的IQueryable<Table1Entity>。- 提前调用
.ToList()会把数据加载到内存执行Union,浪费EF的LINQ to SQL优势,完全没必要。
解决步骤
- 定义统一公共DTO
创建包含两表公共字段的DTO类,作为Union操作的统一输出类型:
public class CommonTableDto { public int Id { get; set; } public string Name { get; set; } public int Status { get; set; } // 补充其他公共字段 }
- 构建数据库层面的Union查询
将两个表的查询都映射到公共DTO,且保持IQueryable状态,让EF在数据库层面执行Union:
var t1Query = db.Table1.Select(x => new CommonTableDto { Id = x.Id, Name = x.Name, Status = x.Status }); var t2Query = db.Table2.Select(x => new CommonTableDto { Id = x.Id, Name = x.Name, Status = x.Status }); var unionQuery = t1Query.Union(t2Query);
- 适配QueryableUtility的泛型类型
- 若
QueryableUtility支持CommonTableDto,直接调整泛型参数:
var utility = new QueryableUtility<CommonTableDto>(); var queryable = utility.findQueryable( Request, unionQuery, QueryParamArray.Instance.FSParameterArray, new CommonTableDto() );
- 若必须使用
Table1Entity作为泛型参数,将公共DTO映射为Table1Entity:
var mappedQuery = unionQuery.Select(dto => new Table1Entity { Id = dto.Id, Name = dto.Name, Status = dto.Status // 映射其他必要字段 }); var utility = new QueryableUtility<Table1Entity>(); var queryable = utility.findQueryable( Request, mappedQuery, QueryParamArray.Instance.FSParameterArray, new Table1Entity() );
内容的提问来源于stack exchange,提问作者Shanmugam R
相关产品推荐
相关产品推荐

