使用AutoMapper映射含嵌套DTO的PreSalesDTO至实体类遇阻求助
解决.NET7中AutoMapper嵌套DTO映射及多表存储问题
1. 明确DTO与实体结构(示例)
先梳理清晰你的DTO和实体类结构,以下是对应场景的示例代码:
DTO类
public class PreSalesDTO { public int Id { get; set; } public string ProjectName { get; set; } // 两个嵌套DTO public CustomerInfoDTO Customer { get; set; } public ProductReqDTO ProductRequest { get; set; } } public class CustomerInfoDTO { public string Name { get; set; } public string Phone { get; set; } } public class ProductReqDTO { public string ProductType { get; set; } public int Quantity { get; set; } }
实体类(对应不同数据表)
public class PreSales { public int Id { get; set; } public string ProjectName { get; set; } // 外键字段 public int CustomerId { get; set; } public int ProductRequestId { get; set; } // EF Core导航属性 public Customer Customer { get; set; } public ProductRequest ProductRequest { get; set; } } public class Customer { public int Id { get; set; } public string Name { get; set; } public string Phone { get; set; } } public class ProductRequest { public int Id { get; set; } public string ProductType { get; set; } public int Quantity { get; set; } }
2. 配置AutoMapper映射规则
创建自定义Profile类,先配置嵌套DTO与实体的映射,再配置主DTO到主实体的映射:
public class PreSalesProfile : Profile { public PreSalesProfile() { // 先配置嵌套DTO到对应实体的映射 CreateMap<CustomerInfoDTO, Customer>(); CreateMap<ProductReqDTO, ProductRequest>(); // 配置主DTO到主实体的映射 CreateMap<PreSalesDTO, PreSales>() // 自动映射导航属性(依赖上面的嵌套映射规则) .ForMember(dest => dest.Customer, opt => opt.MapFrom(src => src.Customer)) .ForMember(dest => dest.ProductRequest, opt => opt.MapFrom(src => src.ProductRequest)) // 外键字段暂时忽略,后续手动赋值(因为需要先保存嵌套实体获取Id) .ForMember(dest => dest.CustomerId, opt => opt.Ignore()) .ForMember(dest => dest.ProductRequestId, opt => opt.Ignore()); } }
3. 注册AutoMapper到DI容器
在Program.cs中注册AutoMapper,确保能通过依赖注入获取IMapper实例:
var builder = WebApplication.CreateBuilder(args); // 注册AutoMapper,指定包含Profile的程序集 builder.Services.AddAutoMapper(typeof(PreSalesProfile));
4. 实现多表存储逻辑
因为要将数据存入不同数据表,需按先保存嵌套实体,再保存主实体的顺序执行,确保外键值正确:
public class PreSalesService { private readonly IMapper _mapper; private readonly AppDbContext _dbContext; public PreSalesService(IMapper mapper, AppDbContext dbContext) { _mapper = mapper; _dbContext = dbContext; } public async Task SavePreSalesAsync(PreSalesDTO dto) { // 映射嵌套DTO到实体 var customer = _mapper.Map<Customer>(dto.Customer); var productRequest = _mapper.Map<ProductRequest>(dto.ProductRequest); // 先保存嵌套实体到对应数据表,获取自增Id _dbContext.Customers.Add(customer); _dbContext.ProductRequests.Add(productRequest); await _dbContext.SaveChangesAsync(); // 映射主DTO到主实体,赋值外键 var preSales = _mapper.Map<PreSales>(dto); preSales.CustomerId = customer.Id; preSales.ProductRequestId = productRequest.Id; // 保存主实体 _dbContext.PreSales.Add(preSales); await _dbContext.SaveChangesAsync(); } }
5. 常见问题排查
- 属性不匹配:如果DTO与实体属性名称不一致,需在对应映射规则中用
ForMember指定映射关系,例如:CreateMap<CustomerInfoDTO, Customer>() .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.CustName)); - 嵌套对象为Null:若DTO中嵌套属性可能为Null,可配置默认值避免映射异常:
CreateMap<PreSalesDTO, PreSales>() .ForMember(dest => dest.Customer, opt => opt.MapFrom(src => src.Customer ?? new CustomerInfoDTO())); - 映射未生效:检查
Profile是否被正确注册,确保AddAutoMapper方法包含了该Profile所在的程序集。 - 外键约束错误:确保EF Core实体间的关系配置正确,外键字段与导航属性的映射符合数据库约束。
内容的提问来源于stack exchange,提问作者Marcio
相关产品推荐
相关产品推荐

