EF Core保存多对多关联本地实体时违反外键约束报错如何解决?
错误原因
该异常的核心原因是:你要插入关联中间表的GroupsId在Groups表中不存在,EF Core尝试写入多对多关联前,对应的Group实体还没有被正确持久化到数据库,或者没有被当前的DbContext正确跟踪。
另外你的业务代码存在笔误:GroupRepository是操作Group集合的仓储类,本身没有Students属性,你应该操作待修改的group实例的Students关联集合。
修复步骤
步骤1:确保Group实体被当前上下文跟踪
分两种场景处理:
- 如果你操作的是全新的未入库的Group:先调用仓储的Add方法将Group加入上下文,再修改关联集合
- 如果你操作的是已存在的游离态Group(比如前端传入、其他上下文查询出来的对象):先通过Id查询出当前上下文跟踪的Group实例,再修改
步骤2:补全Repository缺失的必要方法
你当前的Repository只实现了AddAsync,需要补充查询、Attach、更新等常用方法:
public class Repository<T> : IRepository<T> where T : BaseEntity { private readonly ContractBackendContext _context; public Repository(ContractBackendContext context) { _context = context; } public async Task<T> AddAsync(T entity) { await _context.Set<T>().AddAsync(entity); return entity; } public async Task<T> GetByIdAsync(string id) { return await _context.Set<T>().FindAsync(id); } public void Attach(T entity) { _context.Set<T>().Attach(entity); } public Task UpdateAsync(T entity) { _context.Set<T>().Update(entity); return Task.CompletedTask; } }
步骤3:修正业务代码写法
// 场景1:操作已存在的Group var existGroup = await _unitOfWork.GroupRepository.GetByIdAsync("你要修改的GroupId"); foreach(var student in students) { // 如果student也是游离态,先Attach到上下文,避免EF重复插入Student _unitOfWork.StudentRepository.Attach(student); existGroup.Students.Add(student); } // 场景2:操作全新的Group // var newGroup = new Group // { // Id = "42cfb001-181b-4b0d-89a0-a7aa45e82da7", // // 其他字段赋值 // Students = new List<Student>() // }; // await _unitOfWork.GroupRepository.AddAsync(newGroup); // foreach(var student in students) // { // _unitOfWork.StudentRepository.Attach(student); // newGroup.Students.Add(student); // } await _unitOfWork.SaveChangesAsync();
额外注意
- 如果Student也是全新的未入库对象,需要先调用
StudentRepository.AddAsync将Student加入上下文,或者开启EF Core的级联新增配置,否则会触发Student的外键约束错误 - 被当前上下文跟踪的实体修改关联集合后,不需要手动调用
UpdateAsync方法,EF Core会自动识别变更
内容的提问来源于stack exchange,提问作者RussianPupok Pupok
相关产品推荐
相关产品推荐

