ASP.NET Core仓储模式下GetAll方法中Include后无法使用Select问题
错误原因
- 你的
Include(x=>x.User).Select(x=>x.User.UserName)用法不符合EF Core和泛型仓储的约束:- Include的作用是预加载完整关联实体,Include链后直接加Select会将查询返回类型从
IQueryable<Order>转换为IQueryable<string>,和泛型仓储GetAll方法返回IList<Order>的定义冲突。 - 你定义的
include参数要求返回IIncludableQueryable<T, object>类型,加Select后返回值类型不匹配,直接触发编译错误。
- Include的作用是预加载完整关联实体,Include链后直接加Select会将查询返回类型从
解决方案
方案1:不修改现有泛型仓储(最简方案)
直接正常Include加载User实体,依赖AutoMapper自动映射User.UserName到OrderDTO的对应字段即可,不需要提前做字段筛选:
public async Task<IActionResult> GetAllOrders() { var orders = await _unitOfWork.Orders.GetAll(o => o.IsReady == false, orderBy: item => item.OrderBy(x => x.OrderDate), include:i=>i.Include(x=>x.User)); var results = _mapper.Map<IList<OrderDTO>>(orders); return Ok(results); }
该方案仅会多查询User表的其他字段,绝大多数业务场景下性能影响可忽略。
方案2:仅查询需要的字段(性能最优)
如果你要减少数据库查询的字段量,可以不用现有泛型仓储的GetAll方法,直接用ProjectTo自动生成投影SQL,不需要手动写Select也不需要写Include:
public async Task<IActionResult> GetAllOrders() { var results = await _dbContext.Orders .Where(o => o.IsReady == false) .OrderBy(o => o.OrderDate) .ProjectTo<OrderDTO>(_mapper.ConfigurationProvider) .ToListAsync(); return Ok(results); }
该方案会自动根据OrderDTO的字段定义生成SQL,仅查询需要的字段包括User.UserName,不会查询多余字段。
如果要保留泛型仓储的封装,可以给仓储新增投影查询的重载方法:
public async Task<IList<TResult>> GetAllProjected<TResult>( Expression<Func<T, bool>> expression = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, Expression<Func<T, TResult>> selector = null, Func<IQueryable<T>, IIncludableQueryable<T, object>> include = null) { IQueryable<T> query = _db; if (include != null) query = include(query); if (expression != null) query = query.Where(expression); if (orderBy != null) query = orderBy(query); return await query.Select(selector).AsNoTracking().ToListAsync(); }
内容的提问来源于stack exchange,提问作者Daniel Ashraf
相关产品推荐
相关产品推荐

