当我想引用现有对象时,身份框架会尝试插入新对象

Identity framework tries to insert new object when I want to reference an existing object

我正在使用 blazer 和身份框架制作一个网络应用程序。我希望对象 BoardYear 与作为主席的 Member 具有一对一的关系,这是一个 IdentityUser class 并通过下拉列表选择。

当我尝试插入一个新的 BoardYear 并且令人兴奋的 Member 作为主席时,我得到以下 SQL 异常。

SqlException: Violation of PRIMARY KEY constraint 'PK_AspNetUsers'. Cannot insert duplicate key in object 'dbo.AspNetUsers'. The duplicate key value is (de20c079-ed99-4bf9-9474-d8eb1a05b5b6).

似乎 Entity Framework 想将引用的 Member 添加到数据库中,这是不可能的,因为它已经存在。

会员class:

public class Member : IdentityUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Guid? ChairmanBoardYearId { get; set; }
    public BoardYear ChairmanBoardYear { get; set; }
    ...
}

董事会年class:

public class BoardYear
{
    [Key]
    public Guid BoardYearId { get; set; }
    [DataType(DataType.Date)]
    public DateTime StartDate { get; set; }
    [DataType(DataType.Date)]
    public DateTime EndDate { get; set; }

    public Member Chairman { get; set; }
}

关系在 dbcontext 中配置如下:

public class ApplicationDbContext : IdentityDbContext<Member>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<BoardYear>()
            .HasOne(m => m.Chairman)
            .WithOne(b => b.ChairmanBoardYear)
            .HasForeignKey<Member>(m => m.ChairmanBoardYearId);

            base.OnModelCreating(builder);
    }

    public DbSet<BoardYear> BoardYears { get; set; }
    public DbSet<Commission> Commissions { get; set; }
    public DbSet<CommissionFine> CommissionFines { get; set; }
    public DbSet<MemberFine> MemberFines { get; set; }
    public DbSet<Meeting> Meetings { get; set; }
    public DbSet<MeetingFile> MeetingFiles { get; set; }
    public DbSet<MemberSanction> MemberSanctions { get; set; }
    public DbSet<CommissionSanction> CommissionSanctions { get; set; }
    public DbSet<YearGroup> YearGroups { get; set; }
    public DbSet<CommissionList> CommissionLists { get; set; }
}

编辑下拉列表后,主席在剃须刀页面中的分配方式如下(我可以看到它获得了正确的成员):

async void OnBoardUserChange()
{
    Member selectedMember = await MemberService.FindMember(selectedChairmanId);
    curBoardYear.Chairman = selectedMember;
}

然后在下面的服务中放入数据库:

public class BoardYearService
    {
        private readonly IDbContextFactory<ApplicationDbContext> _contextFactory;
        private readonly DidaDbContext _db;

        public BoardYearService(IDbContextFactory<ApplicationDbContext> contextFactory)
        {
            _contextFactory = contextFactory;
        }

        public async Task<int> Create(BoardYear boardYear)
        {
            using (var ctx = _contextFactory.CreateDbContext())
            {
                CommissionList boardYearCommissionList = new CommissionList();
                boardYear.CommissionList = boardYearCommissionList;
                ctx.BoardYears.Add(boardYear);
                return await ctx.SaveChangesAsync();
            }
        }
    }

问题是您从 MemberService.FindMember 使用的任何上下文实例中检索了用户,但在添加到新上下文实例的 BoardYear 中引用了它。

添加 BoardYear 的第二个上下文实例未跟踪会员,因此假设它是一个添加项。

要么使用通过同一上下文实例检索并持久保存的数据执行整个操作,要么只使用 BoardYear 上的 Id 字段而不是导航 属性。