EF设置外键属性PersonelNumber为null后调用SaveChanges未保存到数据库
问题诱因
当你通过Attach方法附加自行实例化的Cabinet实体时,EF 变更追踪器会默认将实体所有属性标记为未修改状态:
- 你新创建的
Cabinet实例的PersonelNumber属性默认初始值就是null - 当你传入的
cabinet.Employee为null时,赋值后的entity.PersonelNumber还是null,变更追踪器无法检测到「数据库原值为非空、新值为null」的变更,判定该属性无修改,因此SaveChanges时不会生成对应字段的更新语句 - 其他字段(比如值类型的
Number、非空的Location)赋值时和初始默认值存在差异,能被变更追踪器正常识别,因此可以正常更新
解决方案
方案1:先查询现有实体再修改(推荐)
先从数据库加载对应实体,变更追踪器会记录数据库原值,修改为null时能正常识别变更,代码如下:
public int Save(CabinetDto cabinet) { var ctx = this.ContextProviderService.GetE3kContext(); var entity = ctx.Cabinets.First(c => c.Id == cabinet.Id); entity.Location = cabinet.Location; entity.Number = cabinet.Number; entity.PersonelNumber = cabinet.Employee?.PersonelNumber; ctx.SaveChanges(); return entity.Id; }
方案2:主动标记属性为已修改(适合无需查询的高性能场景)
如果不想额外触发一次查询,可手动标记PersonelNumber属性为已修改,强制EF生成对应的更新语句:
public int Save(CabinetDto cabinet) { var ctx = this.ContextProviderService.GetE3kContext(); var entity = new Cabinet {Id = cabinet.Id}; ctx.Cabinets.Attach(entity); entity.Location = cabinet.Location; entity.Number = cabinet.Number; entity.PersonelNumber = cabinet.Employee?.PersonelNumber; // 手动标记外键属性为已修改 ctx.Entry(entity).Property(e => e.PersonelNumber).IsModified = true; ctx.SaveChanges(); return entity.Id; }
可选方案:标记整个实体为已修改
如果需要批量更新多个字段,也可以直接将整个实体标记为已修改,注意该方式会更新所有实体映射的字段,未赋值的字段会被覆盖为实例默认值,需确认业务场景适配:
ctx.Entry(entity).State = EntityState.Modified;
内容的提问来源于stack exchange,提问作者BennoDual
相关产品推荐
相关产品推荐

