EF Core调用SaveChanges时向关联表插入重复记录问题排查求助
问题根源
- 你的
Schedule模型未显式声明外键字段,且前端提交的StorageDataInfo未携带ID值:当前视图仅提交了StorageDataInfo的Name/LicensePlate/BIN三个字段,POST后绑定的StorageDataInfo对象ID为默认值0,EF Core无法识别这是已存在的实体,会将其标记为Added状态同步插入。 - DbContext未追踪传入的
StorageDataInfo对象:你从前端接收的StorageDataInfo没有被当前请求的DbContext追踪,直接将其赋值给新增的Schedule导航属性时,_context.Schedule.Add方法会将整个关联对象图全部标记为新增,导致重复插入tblStorageData表。
修复步骤
1. 完善模型声明,显式添加外键
在Schedule类中增加外键字段,明确关联关系:
[Table("tblSchedule")] public class Schedule { [Required] public int ID { get; set; } [Required] public DateTime ScheduleDateTime { get; set; } public bool Confirmed { get; set; } = false; // 新增显式外键字段 public int StorageDataInfoID { get; set; } public StorageData StorageDataInfo { get; set; } }
2. 视图补充StorageDataInfo.ID隐藏字段
修改cshtml文件,在表单中增加ID的隐藏域,确保POST时能携带已有存储数据的ID:
@Html.HiddenFor(m => m.StorageDataInfo.ID) @Html.HiddenFor(m => m.StorageDataInfo.Name) @Html.HiddenFor(m => m.StorageDataInfo.LicensePlate) @Html.HiddenFor(m => m.StorageDataInfo.BIN)
3. 修改新增逻辑,避免插入关联实体
推荐直接通过外键关联,无需赋值导航属性,从根源避免误插入:
public int AddSchedule(Schedule model) { if (CheckSchedule(model.ScheduleDateTime) >= 4) { return 0; } else { Schedule sch = new Schedule() { ScheduleDateTime = model.ScheduleDateTime, // 直接赋值外键,不赋值导航属性 StorageDataInfoID = model.StorageDataInfo.ID }; _context.Schedule.Add(sch); _context.SaveChanges(); return 1; } }
如果需要保留导航属性赋值的写法,可以手动标记StorageDataInfo为已存在状态:
Schedule sch = new Schedule() { ScheduleDateTime = model.ScheduleDateTime, StorageDataInfo = model.StorageDataInfo }; _context.Schedule.Add(sch); // 手动标记关联实体为未修改,不会插入新数据 _context.Entry(sch.StorageDataInfo).State = EntityState.Unchanged; _context.SaveChanges();
可选优化
为了避免前端篡改ID导致数据异常,可以在新增前先校验StorageDataInfo.ID是否在数据库中存在:
var existStorage = _context.StorageData.FirstOrDefault(s => s.ID == model.StorageDataInfo.ID); if(existStorage == null) { // 非法ID,返回错误 return -1; }
内容的提问来源于stack exchange,提问作者alex cardoso
相关产品推荐
相关产品推荐

