EF Core 2.2.6多对多关联添加时触发主键重复错误求助
EF Core多对多关联添加时报主键重复错误的解决方法
项目环境
- EF Core 2.2.6
- 通过中间表间接实现多对多关联
- 数据库中已存在Course记录
错误信息
尝试向中间表添加记录时,抛出以下异常:
MySql.Data.MySqlClient.MySqlException (0x80004005): Duplicate entry '3945' for key 'PRIMARY'
实体类与中间表代码
public class Course { public long Id { get; set; } // 填充了引用对象及其ID public ICollection<UserCourse> CourseUsers { get; set; } } public class User { public long Id { get; set; } public ICollection<UserCourse> UserCourses { get; set; } } public class UserCourse { public long UserId { get; set; } public User User { get; set; } public long CourseId { get; set; } public Course Course { get; set; } }
Fluent API配置代码
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<UserCourse>() .HasKey(uc => new { uc.UserId, uc.CourseId }); modelBuilder.Entity<UserCourse>() .HasOne(uc => uc.Course) .WithMany(c => c.Users) .HasForeignKey(uc => uc.CourseId); modelBuilder.Entity<UserCourse>() .HasOne(uc => uc.User) .WithMany(c => c.Courses) .HasForeignKey(uc => uc.UserId); }
问题场景
ID为3945的Course记录已存在于数据库中,但添加关联时EF仍尝试向Course表插入这条记录,导致主键重复错误,需求是仅在中间表创建关联,不修改Course表。
解决方案
核心原因
EF Core将传入的Course实例标记为新增状态,而非已存在的跟踪状态,因此保存时会尝试插入重复ID的记录。
具体解决方法
方法一:直接使用ID创建关联(推荐)
无需实例化Course对象,直接指定UserCourse的CourseId为已存在的ID即可,避免EF误判实体状态:
var userCourse = new UserCourse { UserId = 你的用户ID, // 或传入已跟踪的User实例的Id CourseId = 3945 // 直接用已存在的课程ID }; dbContext.UserCourses.Add(userCourse); dbContext.SaveChanges();
方法二:附加Course实体到上下文
如果必须使用Course实体对象,需将其附加到上下文,标记为已存在状态:
var existingCourse = new Course { Id = 3945 }; dbContext.Attach(existingCourse); // 附加后EF将其视为已存在的Unchanged状态 var userCourse = new UserCourse { User = 已跟踪的User实例, // 或设置UserId Course = existingCourse }; dbContext.UserCourses.Add(userCourse); dbContext.SaveChanges();
方法三:修正Fluent API配置的导航属性名
你的配置中存在导航属性名称不匹配的问题:Course类的导航属性是CourseUsers,但配置里写的是.WithMany(c => c.Users);User类的导航属性是UserCourses,配置里写的是.WithMany(c => c.Courses)。这个错误会导致EF无法正确识别关联关系,间接引发状态跟踪问题,必须修正:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<UserCourse>() .HasKey(uc => new { uc.UserId, uc.CourseId }); modelBuilder.Entity<UserCourse>() .HasOne(uc => uc.Course) .WithMany(c => c.CourseUsers) // 改为Course类实际的导航属性名 .HasForeignKey(uc => uc.CourseId); modelBuilder.Entity<UserCourse>() .HasOne(uc => uc.User) .WithMany(u => u.UserCourses) // 改为User类实际的导航属性名 .HasForeignKey(uc => uc.UserId); }
内容的提问来源于stack exchange,提问作者Tauwin
相关产品推荐
相关产品推荐

