Automapper类型映射异常求助:List<Order>转List<OrderDto>报错
错误信息
AutoMapper.AutoMapperMappingException: 映射类型出错。
映射类型:
List1 -> List1
System.Collections.Generic.List1[[Ordering.Domain.Aggregates.OrderAggregate.Order, Ordering.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] -> System.Collections.Generic.List1[[Ordering.Application.Queries.GetOrders.OrderDto, Ordering.Application, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
---> AutoMapper.AutoMapperMappingException: 映射类型出错。
映射类型:
Order -> OrderDto
Ordering.Domain.Aggregates.OrderAggregate.Order -> Ordering.Application.Queries.GetOrders.OrderDto
类型映射配置:
Order -> OrderDto
Ordering.Domain.Aggregates.OrderAggregate.Order -> Ordering.Application.Queries.GetOrders.OrderDto
目标成员:
OrderItems
---> System.NullReferenceException: 对象引用未设置到对象的实例。
在 lambda_method248(Closure , Object , List1 , ResolutionContext ) --- 内部异常堆栈跟踪的结尾 --- 在 lambda_method248(Closure , Object , List1 , ResolutionContext )
--- 内部异常堆栈跟踪的结尾 ---
在 lambda_method248(Closure , Object , List1 , ResolutionContext ) 在 Ordering.Application.Queries.GetOrders.GetOrdersQueryHandler.Handle(GetOrdersQuery request, CancellationToken cancellationToken) 位置 C:\Users\porterc\Documents\Personal Projects\LostChapters\Services\Ordering\Ordering.Application\Queries\GetOrders\GetOrdersQuery.cs:第35行 在 Ordering.Application.Common.Behaviours.TransactionBehaviour2.<>c__DisplayClass4_0.<b__0>d.MoveNext() 位置 C:\Users\porterc\Documents\Personal Projects\LostChapters\Services\Ordering\Ordering.Application\Common\Behaviours\TransactionBehaviour.cs:第50行
--- 来自之前位置的堆栈跟踪结尾 ---
在 Microsoft.EntityFrameworkCore.ExecutionStrategyExtensions.<>c.<b__3_0>d.MoveNext()
--- 来自之前位置的堆栈跟踪结尾 ---
在 Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func4 operation, Func4 verifySucceeded, CancellationToken cancellationToken)
在 Ordering.Application.Common.Behaviours.TransactionBehaviour2.Handle(TRequest request, RequestHandlerDelegate1 next, CancellationToken cancellationToken) 位置 C:\Users\porterc\Documents\Personal Projects\LostChapters\Services\Ordering\Ordering.Application\Common\Behaviours\TransactionBehaviour.cs:第41行
相关代码
GetOrdersQueryHandler
public GetOrdersQueryHandler(IOrderRepository orderRepository, IMapper mapper) { _orderRepository = orderRepository; _mapper = mapper; } public async Task<IEnumerable<OrderDto>> Handle(GetOrdersQuery request, CancellationToken cancellationToken) { var orders = await _orderRepository.GetOrders(); var orderDtos = _mapper.Map<List<OrderDto>>(orders); return orderDtos; }
GetOrders方法
public async Task<IEnumerable<Order>> GetOrders() { return await _orderingDbContext.Orders.Include(oi => oi.OrderItems).OrderBy(o => o.OrderPlaced).ToListAsync(); }
Order类
public class Order : BaseEntity, IAggregateRoot { public int OrderTotal { get; private set; } public DateTime OrderPlaced { get; private set; } public bool OrderPaid { get; private set; } public bool IsCancelled { get; private set; } public string Message { get; private set; } public DeliveryAddress DeliveryAddress { get; private set; } public OrderStatusEnum OrderStatus { get; private set; } public int? PaymentMethodId { get; private set; } public int? CustomerId { get; private set; } private readonly List<OrderItem> _orderItems; public IReadOnlyCollection<OrderItem> OrderItems => _orderItems; protected Order() { _orderItems = new List<OrderItem>(); IsCancelled = false; } public Order(string userId, string userName, DeliveryAddress deliveryAddress, CardTypeEnum cardType, string cardNumber, string cardSecurityNumber, string cardHolderName, DateTime cardExpiration, int? customerId = null, int? paymentMethodId = null) : this() { DeliveryAddress = deliveryAddress; OrderStatus = OrderStatusEnum.Pending; OrderPlaced = DateTime.UtcNow; Message = "New Order Created"; CustomerId = customerId; PaymentMethodId = paymentMethodId; AddOrderCreatedDomainEvent(userId, userName, cardType, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); } }
OrderDto
public record OrderDto : IMapFrom<Order> { public int Id { get; set; } public string Street { get; private set; } public string City { get; private set; } public string Country { get; private set; } public string PostCode { get; private set; } public OrderStatus OrderStatus { get; set; } private readonly List<OrderBookItemsDto> _orderItems; public List<OrderBookItemsDto> OrderItems => _orderItems; public void Mapping(Profile profile) { profile.CreateMap<Order, OrderDto>() .ForMember(dto => dto.Street, opt => opt.MapFrom(p => p.DeliveryAddress.Street)) .ForMember(dto => dto.City, opt => opt.MapFrom(p => p.DeliveryAddress.City)) .ForMember(dto => dto.Country, opt => opt.MapFrom(p => p.DeliveryAddress.Country)) .ForMember(dto => dto.PostCode, opt => opt.MapFrom(p => p.DeliveryAddress.PostCode)) .ForMember(dto => dto.OrderItems, opt => opt.MapFrom(p => p.OrderItems.ToList())); } }
OrderBookItemsDto
public record OrderBookItemsDto: IMapFrom<OrderItem> { public int BookCatalogueId { get; private set; } public decimal BookPrice { get; private set; } public string BookTitle { get; private set; } public string Message { get; private set; } public int Quantity { get; private set; } public void Mapping(Profile profile) { profile.CreateMap<OrderItem, OrderBookItemsDto>(); ; } }
问题分析与解决方案
核心问题
- OrderDto的_orderItems未初始化且为只读:
_orderItems是私有只读字段,未在构造函数中初始化,AutoMapper映射时无法为其赋值,导致空引用异常。 - 部分属性为private set:
Street、City等属性设置为私有写入,AutoMapper默认无法对这类属性赋值。
解决方案
修改OrderDto,调整字段的可访问性并初始化集合:
public record OrderDto : IMapFrom<Order> { public int Id { get; set; } public string Street { get; set; } public string City { get; set; } public string Country { get; set; } public string PostCode { get; set; } public OrderStatus OrderStatus { get; set; } public List<OrderBookItemsDto> OrderItems { get; set; } = new List<OrderBookItemsDto>(); public void Mapping(Profile profile) { profile.CreateMap<Order, OrderDto>() .ForMember(dto => dto.Street, opt => opt.MapFrom(p => p.DeliveryAddress.Street)) .ForMember(dto => dto.City, opt => opt.MapFrom(p => p.DeliveryAddress.City)) .ForMember(dto => dto.Country, opt => opt.MapFrom(p => p.DeliveryAddress.Country)) .ForMember(dto => dto.PostCode, opt => opt.MapFrom(p => p.DeliveryAddress.PostCode)) .ForMember(dto => dto.OrderItems, opt => opt.MapFrom(p => p.OrderItems)); } }
额外说明
- 源Order的
OrderItems是IReadOnlyCollection<OrderItem>,AutoMapper可直接映射为List<OrderBookItemsDto>,无需额外调用ToList()。 - 确保
OrderItem与OrderBookItemsDto的字段名称匹配,若字段名不一致需手动配置映射关系。
内容的提问来源于stack exchange,提问作者Ports

