我在组和访问组之间有 n 对 n 的关系。添加第一条记录时,如果一切正常,则会在 accessgroupGroups 表中创建一条记录,但是在使用附加链接更新集合时出现错误
违反 PRIMARY KEY 约束“PK_AccessGroups”。无法在对象“AccessGroups”中插入重复键。重复键值为 (66822d47-b020-481e-9c61-148457ffb1e6)
并且确实该密钥已经存在于
AccessGroups
表中,因为此操作应该在AccessgroupGroups
表中进行额外记录
[DataContract(IsReference = true)]
public partial class AccessGroup
{
public AccessGroup()
{
Id = Guid.NewGuid();
Users = new List<User>();
Groups = new List<Group>();
}
[DataMember]
public Guid Id { get; set; }
[DataMember]
public Guid? ParentId { get; set; }
[DataMember]
public AccessGroup Parent { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public virtual List<Group> Groups { get; set; }
}
[DataContract(IsReference = true)]
public partial class Group
{
public Group()
{
Id = Guid.NewGuid();
AccessGroups = new List<AccessGroup>();
}
[DataMember]
public Guid Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public virtual List<AccessGroup> AccessGroups { get; set; }
...
}
public class GroupMap : EntityTypeConfiguration<Group>
{
public GroupMap()
{
ToTable("Groups");
HasKey(x => x.Id);
HasOptional(x => x.AccessGroups).WithMany().Map( m=>m.ToTable("AccessGroupGroups"));
}
}
public class AccessGroupMap : EntityTypeConfiguration<AccessGroup>
{
public AccessGroupMap()
{
ToTable("AccessGroups");
HasKey(t => t.Id);
Property(t => t.Name).HasMaxLength(MappingConstants.NameLength);
HasOptional(t => t.Parent).WithMany().HasForeignKey(t => t.ParentId);
HasMany(t => t.Groups)
.WithMany(t => t.AccessGroups)
.Map(m =>
{
m.ToTable("AccessGroupGroups");
m.MapLeftKey("AccessgroupId");
m.MapRightKey("GroupId");
});
}
}
public void SaveGroupAccessGroups(Model.DB.Group group)
{
var existing = db.Groups.Include(x => x.AccessGroups).FirstOrDefault(x => x.Id == group.Id);
if (existing is not null)
{
var old = existing.AccessGroups.Select(x => x.Id).ToList();
existing.AccessGroups.AddRange(group.AccessGroups.Where(y => !existing.AccessGroups.Select(q => q.Id).Contains(y.Id)));
existing.AccessGroups.RemoveAll(x => !group.AccessGroups.Any( y => y.Id == x.Id));
foreach (var q in existing.AccessGroups)
{
db.Entry(q).State = EntityState.Unchanged;
}
db.Commit();
}
}
组和 accessGroups 都已经有多个记录,现在我希望在 AccessGroupGroups 表中添加/更新/删除记录。
这些是导致问题的大部分代码。我想分类地图中应该还有一些东西,但我不知道是什么。希望这里有人有答案。
我还尝试替换现有对象中的所有项目:
existing.AccessGroups.Clear()
existing.AccessGroups.AddRange(group.AccessGroups);
显然问题出在父访问组的链接上,对错误的仔细检查告诉我问题是 EF 试图将链接的访问组的父添加到访问组表中,即使它已经存在,显然。因此,将任何添加的访问组的可选父级的数据库状态标记为
db.Entry(q.Parent).State = EntityState.Unchanged
部分解决了问题,尤其是在多嵌套时。在存储数据之前,我最终将 Parent 项设置为 null。
尽管这种解决方案有点奏效,但我对此并不满意,进一步寻找给了我我猜正确的解决方案
问题是,由于数据通过应用程序传输并因此转换为列表<>,列表与数据库中实际数据之间的实际链接丢失,导致实体框架变得混乱并尝试再次添加记录.
我的最终解决方案看起来像这样
public void SaveGroupAccessGroups(Model.DB.Group group)
{
var existing = db.Groups.Include(x => x.AccessGroups).FirstOrDefault(x => x.Id == group.Id);
if (existing is not null)
{
existing.AccessGroups.Clear();
foreach (var item in group.AccessGroups)
{
var accessGroup = db.AccessGroups.FirstOrDefault(x => x.Id == item.Id && x.DateTimeDeleted == null);
if (accessGroup != null && !existing.AccessGroups.Contains(item))
{
existing.AccessGroups.Add(accessGroup);
}
}
db.Commit();
}
}
我希望这会帮助其他人找到类似问题的解决方案