EF Core 2.0.1多对多关联插入报错:实体跟踪重复键问题
解决EF Core 2.0.1多对多关联插入的跟踪冲突问题
这个错误的核心原因是你手动创建的ReferenciaFabricanteTieneReferenciaConstructor实例都带着IdReferenciaFabricante=0和IdReferenciaConstructor=0的复合键——EF Core的跟踪机制会把这些键值完全相同的实例当成同一个实体,所以循环添加时就触发了"重复跟踪"的错误。而且EF Core 2.x不会自动帮你把新插入主实体(ReferenciaFabricante/ReferenciaConstructor)生成的ID同步到连接实体的外键上,除非你正确建立导航属性关联,或者先保存主实体拿到ID。
下面给出两种常用场景的解决方案:
场景1:同时插入新的主实体并建立关联
这种情况不需要手动将连接实体添加到DbSet,只需要通过导航属性关联,EF会自动处理插入和外键赋值:
// 创建新的制造商实例 var nuevaFabricante = new ReferenciaFabricante { // 填充其他属性 ReferenciaFabricanteTieneReferenciaConstructor = new List<ReferenciaFabricanteTieneReferenciaConstructor>() }; // 创建新的构造商实例 var nuevaConstructor = new ReferenciaConstructor { // 填充其他属性 ReferenciaFabricanteTieneReferenciaConstructor = new List<ReferenciaFabricanteTieneReferenciaConstructor>() }; // 创建连接实体并关联两个主实体 var conexion = new ReferenciaFabricanteTieneReferenciaConstructor { ReferenciaFabricante = nuevaFabricante, ReferenciaConstructor = nuevaConstructor }; // 将连接实体添加到任意一个主实体的导航属性中 nuevaFabricante.ReferenciaFabricanteTieneReferenciaConstructor.Add(conexion); // 只需添加主实体到上下文,EF会自动插入连接实体 _dbContext.ReferenciaFabricante.Add(nuevaFabricante); _dbContext.SaveChanges();
场景2:其中一个主实体已存在,另一个是新插入
如果其中一方已经在数据库中,先确保该实体被EF跟踪,再创建连接实体:
// 获取已存在的构造商(或通过Attach方法附加到上下文) var constructorExistente = _dbContext.ReferenciaConstructor.Find(idConstructor); // 创建新的制造商实例 var nuevaFabricante = new ReferenciaFabricante { // 填充其他属性 ReferenciaFabricanteTieneReferenciaConstructor = new List<ReferenciaFabricanteTieneReferenciaConstructor>() }; // 创建连接实体,关联已存在的构造商和新制造商 var conexion = new ReferenciaFabricanteTieneReferenciaConstructor { ReferenciaConstructor = constructorExistente, ReferenciaFabricante = nuevaFabricante }; nuevaFabricante.ReferenciaFabricanteTieneReferenciaConstructor.Add(conexion); _dbContext.ReferenciaFabricante.Add(nuevaFabricante); _dbContext.SaveChanges();
原代码出错的关键原因
- 所有连接实体的复合键都是
(0,0),EF认为它们是同一个实体,导致跟踪冲突; - 你没有将连接实体与对应的主实体通过导航属性关联,EF无法自动将主实体插入后生成的ID赋值给连接实体的外键。
额外注意事项
- 你的模型配置是正确的,无需修改:
modelBuilder.Entity<ReferenciaFabricanteTieneReferenciaConstructor>() .HasKey(v => new { v.IdReferenciaFabricante, v.IdReferenciaConstructor });
- 如果一定要手动添加连接实体到
DbSet,必须先保存主实体拿到生成的ID,再赋值给连接实体的外键:
// 先保存主实体,获取自动生成的ID _dbContext.ReferenciaFabricante.Add(nuevaFabricante); _dbContext.ReferenciaConstructor.Add(nuevaConstructor); _dbContext.SaveChanges(); // 用生成的ID创建连接实体 var conexion = new ReferenciaFabricanteTieneReferenciaConstructor { IdReferenciaFabricante = nuevaFabricante.Id, IdReferenciaConstructor = nuevaConstructor.Id }; _dbContext.ReferenciaFabricanteTieneReferenciaConstructor.Add(conexion); _dbContext.SaveChanges();
内容的提问来源于stack exchange,提问作者SySc0d3r
相关产品推荐
相关产品推荐

