.NET Core Get API报错:无法将匿名类型转换为PurchaseOrderHeaderDto
问题分析与修复
问题根源
你遇到的InvalidCastException是因为类型不匹配:
在Handle方法的LINQ查询中,你创建了一组匿名类型的对象,但方法需要返回IEnumerable<PurchaseOrderHeaderDto>类型。.NET无法自动将匿名类型转换为自定义的Dto类,因此抛出转换异常。
具体来看这段代码:
var result = (from poList in data join vList in vendorList on poList.VendorId equals vList.Id select new { poList.Id, poList.Date, poList.VendorId, vList.Name }).ToList();
这里select new {...}生成的是.NET自动创建的匿名类型,而非你定义的PurchaseOrderHeaderDto,但后续你试图将这个匿名列表传入期待PurchaseOrderHeaderDto集合的ResultModel.Create()方法,导致类型转换失败。
修复方案
方案1:直接在LINQ中实例化PurchaseOrderHeaderDto
修改LINQ查询,直接创建PurchaseOrderHeaderDto的实例,确保赋值的属性与Dto类的属性名称一致(请根据你的PurchaseOrderHeaderDto实际结构调整属性名):
public async Task<ResultModel<IEnumerable<PurchaseOrderHeaderDto>>> Handle(GetPurchaseOrderListQuery request, CancellationToken cancellationToken) { var data = await _purchaseOrderHeaderRepository.GetAllAsync(); var vendorList = await _vendorRepository.GetAllAsync(); // 直接实例化目标Dto类 var result = (from poList in data join vList in vendorList on poList.VendorId equals vList.Id select new PurchaseOrderHeaderDto { Id = poList.Id, Date = poList.Date, VendorId = poList.VendorId, VendorName = vList.Name // 替换为Dto中对应供应商名称的属性名 }).ToList(); // 直接传入result即可,无需重复ToList() return ResultModel<IEnumerable<PurchaseOrderHeaderDto>>.Create(result); }
方案2:使用映射工具(如AutoMapper)
如果你项目中使用了AutoMapper,可以先查询出数据,再通过映射工具转换为Dto:
- 先配置AutoMapper映射规则(例如在Profile中):
public class PurchaseOrderProfile : Profile { public PurchaseOrderProfile() { CreateMap<(PurchaseOrderHeader Po, Vendor Vendor), PurchaseOrderHeaderDto>() .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Po.Id)) .ForMember(dest => dest.Date, opt => opt.MapFrom(src => src.Po.Date)) .ForMember(dest => dest.VendorId, opt => opt.MapFrom(src => src.Po.VendorId)) .ForMember(dest => dest.VendorName, opt => opt.MapFrom(src => src.Vendor.Name)); // 或者直接从匿名类型映射,只要属性名匹配即可 } }
- 修改Handle方法:
// 注入IMapper private readonly IMapper _mapper; public Handler(IRepository<PurchaseOrderHeader> purchaseOrderHeaderRepository, IRepository<Vendor> vendorRepository, IMapper mapper) { _purchaseOrderHeaderRepository = purchaseOrderHeaderRepository ?? throw new ArgumentNullException(nameof(purchaseOrderHeaderRepository)); _vendorRepository = vendorRepository ?? throw new ArgumentNullException(nameof(vendorRepository)); _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); } public async Task<ResultModel<IEnumerable<PurchaseOrderHeaderDto>>> Handle(GetPurchaseOrderListQuery request, CancellationToken cancellationToken) { var data = await _purchaseOrderHeaderRepository.GetAllAsync(); var vendorList = await _vendorRepository.GetAllAsync(); var queryResult = (from poList in data join vList in vendorList on poList.VendorId equals vList.Id select new { Po = poList, Vendor = vList }).ToList(); // 通过AutoMapper转换为Dto集合 var result = _mapper.Map<IEnumerable<PurchaseOrderHeaderDto>>(queryResult); return ResultModel<IEnumerable<PurchaseOrderHeaderDto>>.Create(result); }
额外优化
原代码中result.ToList()是多余的,因为前面的LINQ查询已经调用了.ToList(),直接传入result即可避免不必要的集合复制。
内容的提问来源于stack exchange,提问作者Farhan Patel
相关产品推荐
相关产品推荐

