我有一个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");
});
当我尝试添加无关的实体并致电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();
有谁知道为什么会这样?
答案 0 :(得分:6)
要添加到Slauma的答案,看起来如果你在其中一个自动多对多事物上设置ICollection属性,EF会感到困惑,并且没有意识到你正在通过这样做来清除集合元素。 / p>
所以不要这样做:
user.Roles = new List<Role>();
user.Roles.Add(role);
你必须这样做:
user.Roles.Clear();
user.Roles.Add(role);
这对我有用。
你不应该这样做。这应该是EF中的一个错误。
答案 1 :(得分:5)
带有User
的{{1}}和带有UserId = 2beaf837-9034-4376-9510-b1609c54efbe
的{{1}}处于状态Role
的事实并不意味着没有任何内容写入数据库。
特别是对于多对多关系(通常用于独立关联),EF维护关系本身的状态,这与实体状态不同。如果条目被插入到链接表中,则意味着所讨论的两个实体的关系条目处于状态RoleId = dcd16d00-d46e-4d48-8328-3e7b35b11ccf
,尽管这些实体的实体状态是Unchanged
。在枚举Added
s Unchanged
时,您无法看到关系条目。它只会返回实体状态。您必须转到底层DbContext
以查询关系状态。
示例:
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();
}
都处于状态user
,但仍会在链接表中插入记录。如果用户1和角色5已在数据库中链接,则此代码将抛出异常。
添加role
与问题无关。只有对Unchanged
的调用才会导致异常,因为您很可能在问题的代码段之前的某个位置创建了两个实体之间的关系。
答案 2 :(得分:1)
您正尝试在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.
检查哪个用户的ID为2beaf837-9034-4376-9510-b1609c54efbe,以及哪个角色的ID为dcd16d00-d46e-4d48-8328-3e7b35b11ccf。 如果您确定自己只输入了一次该用户,那么在没有意识到的情况下多次插入被调用数据的方法是什么?
答案 3 :(得分:0)
希望有人发现它有用我发现改变EF中的现有列表与创建新列表之间存在很大差异。
在这种情况下,我正在进行更新,并认为最简单的方法是构建我想要的项目的新列表。但是如果某些项目已经添加到列表中,我会在保存时遇到主键违规。
我最终保留了相同的列表并对其进行了修改。清除它并读取是正常的,创建一个新的列表不是。