在Entity Framework代码第一个链接表中违反PRIMARY KEY约束

97l*_*ave 10 .net c# entity-framework ef-code-first

我有一个User表和一个Roles表.有一个自动生成的UsersRoles链接表,其中包含User和Roles表中的Id.这是使用以下代码生成的:

modelBuilder.Entity<User>()
                .HasMany(u => u.Roles)
                .WithMany(r => r.Users)
                .Map(c => { 
                    c.MapLeftKey("UserId");
                    c.MapRightKey("RoleId");
                    c.ToTable("UsersRoles");
                });
Run Code Online (Sandbox Code Playgroud)

当我尝试添加不相关的实体并调用时,Context.SaveChanges()我收到以下错误:

违反PRIMARY KEY约束'PK_UsersRoles'.无法在对象'dbo.UsersRoles'中插入重复键.重复键值为(2beaf837-9034-4376-9510-b1609c54efbe,dcd16d00-d46e-4d48-8328-3e7b35b11ccf).该语句已终止.

我检查了Conext.ChangeTracker.Entries()错误中提到的项目,实体状态被标记为未更改.

标记为已添加的唯一实体是我要添加的新记录,其他所有内容都标记为未更改.

添加实体的代码:

 RoleGroup group = Context.RoleGroups.Create();
 group.Title = roleGroupName;
 Context.Set<RoleGroup>().Add(group);
 Context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

有谁知道为什么会这样?

N73*_*73k 6

要添加到Slauma的答案,看起来如果你在其中一个自动多对多事物上设置ICollection属性,EF就会感到困惑,并且没有意识到你是通过这样做来清除集合元素.

所以不要这样做:

user.Roles = new List<Role>();
user.Roles.Add(role);
Run Code Online (Sandbox Code Playgroud)

你必须这样做:

user.Roles.Clear();
user.Roles.Add(role);
Run Code Online (Sandbox Code Playgroud)

这对我有用.

你不应该这样做.这应该是EF中的一个错误.


Sla*_*uma 5

该事实User与UserId = 2beaf837-9034-4376-9510-b1609c54efbe和Role与RoleId = dcd16d00-d46e-4d48-8328-3e7b35b11ccf在状态Unchanged并不意味着没有被写入到数据库中.

特别是对于多对多关系(通常用于独立关联),EF维护关系本身的状态,该状态与实体状态不同.如果条目被插入到链接表中,则意味着所讨论的两个实体的关系条目处于状态,Added尽管这些实体的实体状态是Unchanged.枚举DbContexts 时,您无法看到关系条目ChangeTracker.它只会返回实体状态.您必须转到底层ObjectContext以查询关系状态.

例:

using (var ctx = new MyContext())
{
    var user = ctx.Users.Find(1);
    var role = ctx.Roles.Find(5);

    user.Roles = new List<Role>();
    user.Roles.Add(role);

    ctx.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)

这里user和role将处于状态Unchanged,但仍然将记录插入到链接表中.如果用户1和角色5已在数据库中链接,则此代码将抛出异常.

添加group与问题无关.只有调用才会SaveChanges导致异常,因为您很可能在问题中的代码段之前的某个位置创建了两个实体之间的关系.