Entity Framework 在添加 n 到 n 关系时导致目标表上的主键约束

问题描述 投票:0回答:1

我在组和访问组之间有 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);
entity-framework-6 many-to-many
1个回答
0
投票

显然问题出在父访问组的链接上,对错误的仔细检查告诉我问题是 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();
    }
}

我希望这会帮助其他人找到类似问题的解决方案

© www.soinside.com 2019 - 2024. All rights reserved.