.NET Core 7中如何通过AutoMapper忽略空值?
如何通过AutoMapper全局忽略未填写的空值字段
我使用.NET Core 7.0和AutoMapper 12,通过Postman向Company表发送如下JSON:
{ "id": 1002, "name": "xcv" }
但未提交的字段(比如description)会被自动设为null更新到数据库。我希望通过AutoMapper全局配置,忽略CompanyUpdateDto中用户未填写的空值,但现有配置没生效。相关代码如下:
相关代码
Company实体
public class Company { public int Id { get; set; } public string? Name { get; set; } public string? Description { get; set; } public DateTime? CreatedDate { get; set; } public DateTime? UpdatedDate { get; set; } }
CompanyUpdateDto类
public class CompanyUpdateDto { public int Id { get; set; } public string? Name { get; set; } public string? Description { get; set; } public DateTime? UpdatedDate { get; set; } }
Program.cs配置
builder.Services.AddAutoMapper(typeof(AutoMapperProfile));
AutoMapper配置类(原配置)
public class AutoMapperProfile : Profile { public AutoMapperProfile() { AllowNullCollections = true; #region Company DTO CreateMap<Company, CompanyDto>().ReverseMap(); CreateMap<Company, CompanyCreateDto>().ReverseMap(); //CreateMap<Company, CompanyUpdateDto>().ReverseMap(); CreateMap<Company, CompanyUpdateDto>().ReverseMap().ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null)); #endregion } }
解决方案
核心问题分析
当前配置未生效的原因:
- 映射方向错误:更新场景是从
CompanyUpdateDto映射到Company实体,原配置基于Company→CompanyUpdateDto反向生成,逻辑方向不匹配。 - 未处理可空值类型:比如
DateTime?这类类型,仅判断srcMember != null无法区分“未设置值”和“有实际值”的情况。
全局配置实现
修改AutoMapper配置类,通过ForAllMaps全局针对所有命名包含UpdateDto的类生效,忽略源字段为空/未设置的情况:
public class AutoMapperProfile : Profile { public AutoMapperProfile() { AllowNullCollections = true; // 全局配置:所有UpdateDto到实体的映射,忽略空值/未设置的字段 ForAllMaps((map, opts) => { if (map.SourceType.Name.EndsWith("UpdateDto")) { opts.ForAllMembers(memberOpts => { memberOpts.Condition((src, dest, srcMember) => { // 排除null值 if (srcMember == null) return false; // 处理可空值类型(如DateTime?),仅当有实际值时才映射 var nullableType = Nullable.GetUnderlyingType(srcMember.GetType()); if (nullableType != null) { return ((System.Nullable)srcMember).HasValue; } // 非可空值类型(如int Id)强制映射 return true; }); }); } }); #region Company DTO CreateMap<Company, CompanyDto>().ReverseMap(); CreateMap<Company, CompanyCreateDto>().ReverseMap(); // 仅配置UpdateDto到实体的映射,无需反向 CreateMap<CompanyUpdateDto, Company>(); #endregion } }
业务逻辑配合
必须确保更新操作是将DTO映射到从数据库查询到的现有实体,而非创建新实体:
// 示例更新逻辑 public async Task UpdateCompany(CompanyUpdateDto dto) { // 获取数据库中已存在的实体 var existingCompany = await _context.Companies.FindAsync(dto.Id); if (existingCompany == null) { throw new KeyNotFoundException("Company not found"); } // 将DTO的非空字段映射到现有实体 _mapper.Map(dto, existingCompany); // 保存变更 await _context.SaveChangesAsync(); }
额外说明
如果需要区分“用户主动提交null”和“未提交字段”,推荐使用JsonPatchDocument处理部分更新,此时无需AutoMapper空值忽略配置,因为Patch文档只会更新指定字段。
内容的提问来源于stack exchange,提问作者fatihgun
相关产品推荐
相关产品推荐

