ASP.NET Web API中AutoMapper未忽略可空布尔值问题排查
可空布尔类型在AutoMapper中未被忽略的问题解析
问题场景
基于.NET 6开发ASP.NET Web API的餐厅信息修改功能,核心实体Restaurant的HasDelivery是非可空布尔类型,请求DTOModifyRestaurantDto中对应属性为可空布尔类型。配置AutoMapper仅映射非null值后,字符串类型属性正常生效,但可空布尔值始终被转为false,未被忽略。
相关代码
Restaurant实体类
public class Restaurant { public int Id { get; set; } public string Name { get; set; } public string? Description { get; set; } public string Category { get; set; } public bool HasDelivery { get; set; } public string ContactEmail { get; set; } public string ContactNumber { get; set; } public int? CreatedById { get; set; } public virtual User CreatedBy { get; set; } public int AddressId { get; set; } public virtual Address Address { get; set; } public virtual List<Dish> Dishes { get; set; } }
ModifyRestaurantDto类
public class ModifyRestaurantDto { [MaxLength(25)] public string? Name { get; set; } [MaxLength(100)] public string? Description { get; set; } public bool? HasDelivery { get; set; } }
UpdateAsync方法
public async Task UpdateAsync(int id, ModifyRestaurantDto modifyRestaurantDto) { var restaurant = await _dbContext .Restaurants .FirstOrDefaultAsync(r => r.Id == id) ?? throw new NotFoundException("Restaurant not found..."); var authorizationResult = _authorizationService .AuthorizeAsync( _userContextService.User, restaurant, new ResourceOperationRequirement(ResourceOperation.Update)) .Result; if (!authorizationResult.Succeeded) throw new ForbidException(); _mapper.Map(modifyRestaurantDto, restaurant); await _dbContext.SaveChangesAsync(); }
AutoMapper配置
public class RestaurantMappingProfile : Profile { public RestaurantMappingProfile() { CreateMap<ModifyRestaurantDto, Restaurant>() .ForAllMembers(opts => opts.Condition((src, dest, value) => value is not null)); } }
问题原因
问题出在AutoMapper的Condition参数逻辑上:当DTO中的HasDelivery为null时,AutoMapper会先将这个可空布尔值转换为目标属性(非可空bool)的默认值false,再把这个转换后的false传入Condition的value参数中。此时value is not null判断为true,所以会执行映射,将false覆盖到实体的HasDelivery属性上,导致原本的属性值被修改。
解决方案
方案一:全局修改判断逻辑,直接检查源属性值
修改AutoMapper配置,通过上下文获取源对象的原始属性值,避免转换后的默认值干扰:
public class RestaurantMappingProfile : Profile { public RestaurantMappingProfile() { CreateMap<ModifyRestaurantDto, Restaurant>() .ForAllMembers(opts => opts.Condition((src, dest, _, context) => { // 获取源对象当前属性的原始值 var srcProperty = context.MemberMap.SourceMember; var srcValue = srcProperty.GetValue(src); return srcValue != null; })); } }
方案二:单独针对可空布尔属性配置条件
如果只需要处理HasDelivery属性,可单独为其设置判断条件,其他属性保持原有逻辑:
public class RestaurantMappingProfile : Profile { public RestaurantMappingProfile() { CreateMap<ModifyRestaurantDto, Restaurant>() // 仅当源属性有值时才映射HasDelivery .ForMember(dest => dest.HasDelivery, opt => opt.Condition(src => src.HasDelivery.HasValue)) // 其他属性保持原有非null判断 .ForAllOtherMembers(opts => opts.Condition((src, dest, value) => value is not null)); } }
内容的提问来源于stack exchange,提问作者BartTux
相关产品推荐
相关产品推荐

