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

时间:2022-10-05 15:23:19

I have a User table and a Roles table. There is a automatically generated UsersRoles link table which contains the Id from the User and Roles tables. This is generated using the following code:

我有一个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");
                });

When I am trying to add an unrelated Entity and call Context.SaveChanges() I receive the following error:

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

Violation of PRIMARY KEY constraint 'PK_UsersRoles'. Cannot insert duplicate key in object 'dbo.UsersRoles'. The duplicate key value is (2beaf837-9034-4376-9510-b1609c54efbe, dcd16d00-d46e-4d48-8328-3e7b35b11ccf). The statement has been terminated.

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

I have checked the Conext.ChangeTracker.Entries() for the items mentioned in the error and the Entity State is marked as Unchanged.

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

The only Entity that is marked as Added is the new record I am trying to add, everything else is marked as Unchanged.

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

Code for adding Entity:

添加实体的代码:

 RoleGroup group = Context.RoleGroups.Create();
 group.Title = roleGroupName;
 Context.Set<RoleGroup>().Add(group);
 Context.SaveChanges();

Does anyone know why this is happening?

有谁知道为什么会这样?

4 个解决方案

#1


5  

The fact that the User with UserId = 2beaf837-9034-4376-9510-b1609c54efbe and the Role with RoleId = dcd16d00-d46e-4d48-8328-3e7b35b11ccf are in state Unchanged does not mean that nothing gets written to the database.

具有UserId = 2beaf837-9034-4376-9510-b1609c54efbe的用户和具有RoleId = dcd16d00-d46e-4d48-8328-3e7b35b11ccf的角色处于未更改状态并不意味着没有任何内容写入数据库。

Especially for many-to-many relationships (generally for independent associations) EF maintains a state for the relationship itself which is different from the entity state. If an entry gets inserted into the link table it means that the relationship entry for the two entities in question is in state Added although the entity state for those entities is Unchanged. You cannot see the relationship entry when enumerating the DbContexts ChangeTracker. It will only return entity states. You have to go down to the underlying ObjectContext to query for the relationship state.

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

Example:

例:

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();
}

Here user and role will be both in state Unchanged, but still a record is inserted into the link table. And this code will throw your exception if user 1 and role 5 are already linked in the database.

这里用户和角色都处于未更改状态,但仍然会在链接表中插入记录。如果用户1和角色5已在数据库中链接,则此代码将抛出异常。

Adding the group has nothing to do with the problem. Only the call to SaveChanges is causing the exception because you most likely have created a relationship between the two entities somewhere before the code snippet in your question.

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

#2


6  

To add to Slauma's answer, it looks like if you set the ICollection property on one of these auto many-to-many things, EF gets confused and doesn't realize that you are clearing the collections elements by doing this.

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

So instead of doing this:

所以不要这样做:

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

You have to do this:

你必须这样做:

user.Roles.Clear();
user.Roles.Add(role);

This worked for me.

这对我有用。

You shouldn't have to do this though. This should be a bug in EF.

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

#3


1  

You are trying to insert the same combination of user / role into the UserRoles table:

您正尝试将相同的用户/角色组合插入UserRoles表:

Violation of PRIMARY KEY constraint 'PK_UsersRoles'. Cannot insert duplicate key in object 'dbo.UsersRoles'. The duplicate key value is (2beaf837-9034-4376-9510-b1609c54efbe, dcd16d00-d46e-4d48-8328-3e7b35b11ccf). The statement has been terminated.

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

Check to see which user has the ID of 2beaf837-9034-4376-9510-b1609c54efbe, and which role has the ID of dcd16d00-d46e-4d48-8328-3e7b35b11ccf. If you are sure you've only entered that user once, is the method that inserts the data being called more than once without you realising?

检查哪个用户的ID是2beaf837-9034-4376-9510-b1609c54efbe,以及哪个角色的ID为dcd16d00-d46e-4d48-8328-3e7b35b11ccf。如果您确定只输入了该用户一次,那么在没有意识到的情况下插入被调用数据的方法是多次?

#4


0  

Hoping that someone will find it helpful I discovered that there's a big difference between altering an existing list in EF compared to creating a new list.

希望有人会发现它有用我发现改变EF中的现有列表与创建新列表之间存在很大差异。

In this case I was making an update and thought it easiest to just build a new list of the items I wanted. But if some of the items were already added to the list I would get a primary key violation while saving.

在这种情况下,我正在进行更新,并认为最简单的方法是建立一个我想要的项目的新列表。但是如果某些项目已经添加到列表中,我会在保存时遇到主键违规。

I ended up keeping the same list and just making modifications to it. Clearing it and readding was ok, creating a new list was not.

我最终保留了相同的列表,只是对它进行了修改。清除它并读取是正常的,创建一个新的列表不是。

#1


5  

The fact that the User with UserId = 2beaf837-9034-4376-9510-b1609c54efbe and the Role with RoleId = dcd16d00-d46e-4d48-8328-3e7b35b11ccf are in state Unchanged does not mean that nothing gets written to the database.

具有UserId = 2beaf837-9034-4376-9510-b1609c54efbe的用户和具有RoleId = dcd16d00-d46e-4d48-8328-3e7b35b11ccf的角色处于未更改状态并不意味着没有任何内容写入数据库。

Especially for many-to-many relationships (generally for independent associations) EF maintains a state for the relationship itself which is different from the entity state. If an entry gets inserted into the link table it means that the relationship entry for the two entities in question is in state Added although the entity state for those entities is Unchanged. You cannot see the relationship entry when enumerating the DbContexts ChangeTracker. It will only return entity states. You have to go down to the underlying ObjectContext to query for the relationship state.

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

Example:

例:

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();
}

Here user and role will be both in state Unchanged, but still a record is inserted into the link table. And this code will throw your exception if user 1 and role 5 are already linked in the database.

这里用户和角色都处于未更改状态,但仍然会在链接表中插入记录。如果用户1和角色5已在数据库中链接,则此代码将抛出异常。

Adding the group has nothing to do with the problem. Only the call to SaveChanges is causing the exception because you most likely have created a relationship between the two entities somewhere before the code snippet in your question.

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

#2


6  

To add to Slauma's answer, it looks like if you set the ICollection property on one of these auto many-to-many things, EF gets confused and doesn't realize that you are clearing the collections elements by doing this.

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

So instead of doing this:

所以不要这样做:

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

You have to do this:

你必须这样做:

user.Roles.Clear();
user.Roles.Add(role);

This worked for me.

这对我有用。

You shouldn't have to do this though. This should be a bug in EF.

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

#3


1  

You are trying to insert the same combination of user / role into the UserRoles table:

您正尝试将相同的用户/角色组合插入UserRoles表:

Violation of PRIMARY KEY constraint 'PK_UsersRoles'. Cannot insert duplicate key in object 'dbo.UsersRoles'. The duplicate key value is (2beaf837-9034-4376-9510-b1609c54efbe, dcd16d00-d46e-4d48-8328-3e7b35b11ccf). The statement has been terminated.

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

Check to see which user has the ID of 2beaf837-9034-4376-9510-b1609c54efbe, and which role has the ID of dcd16d00-d46e-4d48-8328-3e7b35b11ccf. If you are sure you've only entered that user once, is the method that inserts the data being called more than once without you realising?

检查哪个用户的ID是2beaf837-9034-4376-9510-b1609c54efbe,以及哪个角色的ID为dcd16d00-d46e-4d48-8328-3e7b35b11ccf。如果您确定只输入了该用户一次,那么在没有意识到的情况下插入被调用数据的方法是多次?

#4


0  

Hoping that someone will find it helpful I discovered that there's a big difference between altering an existing list in EF compared to creating a new list.

希望有人会发现它有用我发现改变EF中的现有列表与创建新列表之间存在很大差异。

In this case I was making an update and thought it easiest to just build a new list of the items I wanted. But if some of the items were already added to the list I would get a primary key violation while saving.

在这种情况下,我正在进行更新,并认为最简单的方法是建立一个我想要的项目的新列表。但是如果某些项目已经添加到列表中,我会在保存时遇到主键违规。

I ended up keeping the same list and just making modifications to it. Clearing it and readding was ok, creating a new list was not.

我最终保留了相同的列表,只是对它进行了修改。清除它并读取是正常的,创建一个新的列表不是。