如何仅更新传入ViewModel中的指定字段而不将未传字段置空
问题根因
默认情况下,.NET 模型绑定处理API请求时,如果请求报文中没有包含ViewModel对应属性的参数,会自动给该属性赋值为对应类型的默认值,string类型的默认值就是null。如果你直接把绑定后的ViewModel全量覆盖到数据库实体上,就会导致未传参的字段被覆盖为null。
可行解决方案
方案1:使用JSON Patch实现局部更新(官方推荐,适用所有局部更新场景,支持显式将字段设为null的需求)
- 安装依赖包
Microsoft.AspNetCore.Mvc.NewtonsoftJson,JSON Patch依赖Newtonsoft.Json实现 - Program.cs中注册NewtonsoftJson支持:
builder.Services.AddControllers().AddNewtonsoftJson();- 接口参数改为JsonPatchDocument类型:
public async Task<IActionResult> UpdateUser(int id, [FromBody] JsonPatchDocument<UserUpdateViewModel> patchDoc) { // 先查询原有实体 var user = await _context.Users.FindAsync(id); if (user == null) return NotFound(); // 应用Patch变更,仅更新传入的字段 patchDoc.ApplyTo(user); await _context.SaveChangesAsync(); return Ok(); }对应的请求格式需要改为PATCH类型,报文示例:
[ { "op": "replace", "path": "/name", "value": "my name" } ]- 安装依赖包
方案2:手动判断非null字段再赋值(简单易用,适用字段较少的场景)
先查询数据库中的原有实体,仅将ViewModel中不为null的字段赋值到实体上:var existingUser = await _context.Users.FindAsync(id); if (existingUser == null) return NotFound(); // 仅更新非null字段 if (viewModel.Name != null) existingUser.Name = viewModel.Name; if (viewModel.Email != null) existingUser.Email = viewModel.Email; if (viewModel.Phone != null) existingUser.Phone = viewModel.Phone; await _context.SaveChangesAsync();注意:如果业务支持将字段主动设置为null,此方案会失效,推荐用方案1
方案3:使用AutoMapper条件映射(适用字段较多的场景,减少重复代码)
配置AutoMapper映射规则时,指定仅当源属性不为null时才执行映射:CreateMap<UserUpdateViewModel, User>() .ForAllMembers(opts => opts.Condition((src, dest, srcValue) => srcValue != null));映射时直接使用原有实体作为映射目标即可:
_mapper.Map(viewModel, existingUser);
内容的提问来源于stack exchange,提问作者Fachrul Rozi
相关产品推荐
相关产品推荐

