ASP.NET Core Web API中AutoMapper映射无结果问题排查
ASP.NET Core Web API中AutoMapper自动映射失败,手动映射正常的原因分析
问题场景
在ASP.NET Core Web API中使用AutoMapper实现Order、OrderProduct、Product实体到对应DTO的映射时,自动映射返回的OrderDTO中OrderProductDTO列表为空,但手动遍历映射能得到正确结果。
实体类代码
public class Order { public Order() { OrderDate = DateTime.Now; } public int Id { get; set; } public DateTime OrderDate { get; set; } public AppUser AppUser { get; set; } public ICollection<OrderProduct> OrderProducts { get; set; } = new HashSet<OrderProduct>(); } public class OrderProduct { public int Id { get; set; } public int OrderId { get; set; } public Order Order { get; set; } public int ProductId { get; set; } public Product Product { get; set; } } public class Product { public int Id { get; set; } [Required, MaxLength(150)] public string PName { get; set; } [Required, MaxLength(250)] public string PDescription { get; set; } public decimal Price { get; set; } }
DTO类代码
public class OrderDTO { public int OrderId { get; set; } public DateTime OrderDate { get; set; } public string ProductName { get; set; } public List<OrderProductDTO> OrderProductDTO { get; set; } = new List<OrderProductDTO>(); } public class OrderProductDTO { public int OrderId { get; set; } public ProductDTO Products { get; set; } public int ProductId { get; set; } public string ProductName { get; set; } public decimal Price { get; set; } public int Quantity { get; set; } } public class ProductDTO { public int productID { get; set; } public string productName { get; set; } public decimal productPrice { get; set; } public int productRating { get; set; } public string productImageURL { get; set; } }
AutoMapper配置
CreateMap<Order, OrderDTO>() .ForMember(dest => dest.OrderId, opt => opt.MapFrom(src => src.Id)) .ReverseMap(); CreateMap<OrderProduct, OrderProductDTO>() .ForMember(dest => dest.ProductName, opt => opt.MapFrom(src => src.Product.PName)) .ForMember(dest => dest.OrderId , opt => opt.MapFrom(src => src.OrderId)) .ForMember(dest => dest.ProductId, opt => opt.MapFrom(src => src.Product.Id)) .ReverseMap(); CreateMap<Product, ProductDTO>() .ForMember(dsc => dsc.productID, src => src.MapFrom(src => src.Id)) .ForMember(dsc => dsc.productName, src => src.MapFrom(src => src.PName)) .ForMember(dsc => dsc.productPrice, src => src.MapFrom(src => src.Price)) .ForMember(dsc => dsc.productImageURL, src => src.MapFrom(src => src.ImageUrl)) .ForMember(dsc => dsc.productRating, src => src.MapFrom(src => src.Rate)) .ReverseMap();
控制器关键代码
public async Task<IReadOnlyList<Order>> GetOrdersByUsernameAsync(string username) { return await _context.Set<Order>() .Include(o => o.OrderProducts) .ThenInclude(op => op.Product) .Where(o => o.AppUser.Id == username) .ToListAsync(); } [HttpGet("{userID}")] public async Task<IActionResult> GetOrdersByUserId(string userID) { var orders = await unitOfWork.Orders.GetOrdersByUsernameAsync(userID); if (orders == null) { return BadRequest($"There is no order yet or not found.."); } // 自动映射代码(当前返回空的OrderProductDTO列表) // var result = _mapper.Map<IEnumerable<OrderDTO>>(orders); // return Ok(result); // 手动映射代码(正常返回) var orderDTOs = new List<OrderDTO>(); foreach (var order in orders) { var orderDTO = new OrderDTO { OrderId = order.Id, OrderProductDTO = new List<OrderProductDTO>() }; foreach (var orderProduct in order.OrderProducts) { var orderProductDTO = new OrderProductDTO { ProductId = orderProduct.ProductId, ProductName = orderProduct.Product.PName, Price = orderProduct.Product.Price, Quantity = orderProduct.Product.Quantity, }; orderDTO.OrderProductDTO.Add(orderProductDTO); } orderDTOs.Add(orderDTO); } return Ok(orderDTOs); }
映射结果对比
- 未映射的原始实体结果:包含完整的
OrderProducts及关联Product数据 - 手动映射结果:
OrderProductDTO列表数据完整 - AutoMapper自动映射结果:
OrderProductDTO列表为空
原因分析
核心问题是属性名称不匹配且未显式配置集合映射:
Order实体中的集合属性名为OrderProducts,而OrderDTO中的对应集合属性名为OrderProductDTO,两者名称差异较大,AutoMapper无法自动识别匹配关系。- 现有
Order到OrderDTO的映射配置仅处理了OrderId字段,未对OrderProducts到OrderProductDTO的集合映射进行显式配置。
解决方案
修改Order到OrderDTO的映射配置,添加集合属性的显式映射:
CreateMap<Order, OrderDTO>() .ForMember(dest => dest.OrderId, opt => opt.MapFrom(src => src.Id)) // 显式配置集合映射,AutoMapper会自动使用已有的OrderProduct→OrderProductDTO映射规则 .ForMember(dest => dest.OrderProductDTO, opt => opt.MapFrom(src => src.OrderProducts)) .ReverseMap();
配置完成后,AutoMapper会自动将Order.OrderProducts中的每个OrderProduct实例映射为OrderProductDTO,并填充到OrderDTO.OrderProductDTO列表中,最终得到与手动映射一致的结果。
内容的提问来源于stack exchange,提问作者Tom Adam
相关产品推荐
相关产品推荐

