修复Automapper.Extensions.OData单结果查询返回空值问题
问题分析
GetById接口返回空值的核心原因是Automapper配置了ForAllMembers(opt => opt.ExplicitExpansion()),这个配置要求所有字段必须显式指定展开才能被映射。GetOrdersAsync用了GetQueryAsync方法,它会自动解析OData的$select/$expand参数并传递给Automapper,所以能正常返回数据;但GetOrderByIdMapperAsync里直接用ProjectTo时没有指定任何要展开的成员,导致所有字段都没被映射,最终返回空对象。
解决方案
有两种可行的解决方式,根据需求选择:
方式一:显式指定要展开的成员
如果不需要支持OData动态查询参数(如$select),可以直接在ProjectTo中指定需要映射的字段:
修改仓储层代码
public async Task<OrderDto?> GetOrderByIdMapperAsync(int id) { return await _context.Orders .Where(x => x.Id == id) .ProjectTo<OrderDto>(_mapper.ConfigurationProvider, null, dest => dest.Id, dest => dest.Name, dest => dest.Description, dest => dest.CategoryName, dest => dest.OrderStatus) .SingleOrDefaultAsync(); }
这种方式会强制映射指定的所有字段,适合不需要动态选择字段的场景。
方式二:结合ODataQueryOptions处理(推荐)
如果想让GetById接口也支持OData动态查询参数(如$select、$expand),可以复用GetQueryAsync的逻辑,再结合SingleOrDefaultAsync:
第一步:修改仓储层方法,接收ODataQueryOptions
public async Task<OrderDto?> GetOrderByIdMapperAsync(int id, ODataQueryOptions<OrderDto> options) { // 先过滤指定ID的订单,再应用OData查询和Automapper映射 var query = _context.Orders.Where(x => x.Id == id); var mappedQuery = query.GetQueryAsync(_mapper, options).Result; return await mappedQuery.SingleOrDefaultAsync(); }
说明:
GetQueryAsync实际返回的是IQueryable<TDto>而非异步任务,因此直接访问Result即可,无需await。若使用新版本Automapper.Extensions.OData,该方法可能已重命名为ProjectToQueryable,用法一致。
第二步:修改控制器代码,传递ODataQueryOptions
[EnableQuery] public async Task<ActionResult<OrderDto?>> Get([FromODataUri] int key, ODataQueryOptions<OrderDto> options) { return await _orderRepository.GetOrderByIdMapperAsync(key, options); }
这种方式与GetOrdersAsync逻辑保持一致,支持动态选择字段和展开导航属性,符合OData设计理念。
内容的提问来源于stack exchange,提问作者Wicked
相关产品推荐
相关产品推荐

