代码之家  ›  专栏  ›  技术社区  ›  zameb

在SaveChanges之前添加相关实体时与外键冲突

  •  0
  • zameb  · 技术社区  · 6 年前

    如果我试图添加一个根本不存在的相关实体,我预计EF.6 2.0会失败。但在本例中,有问题的相关实体(Person)是在SaveChanges之前添加到上下文中的(还不在Db中,但我看到是在ChangeManager中)。

    我用几节课再现了我的问题:

    public class Person
    {
        public Guid Id { get; set; }
    }
    

    以及:

    public class AuditPerson
    {
        public Guid AuditId { get; set; }
        public Guid PersonId { get; set; }
        public DateTime Timestamp { get; set; }
    }
    

    上下文是:

    public class PersonTestContext : DbContext
    {
        public DbSet<Person> Packages { get; set; }
        public DbSet<AuditPerson> PersonAudits { get; set; }
    
        public PersonTestContext() : base("PersonTestDb")
        {
            Database.SetInitializer<PersonTestContext>(null);
        }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Person>()
                .ToTable("Person", "person")
                .HasKey(t => t.Id);
    
            modelBuilder.Entity<AuditPerson>()
                .ToTable("AuditPerson", "dbo")
                .HasKey(ap => new { ap.AuditId, ap.PersonId });
    
            base.OnModelCreating(modelBuilder);
        }
    }
    

        static void Main(string[] args)
        {
            using (var context = new PersonTestContext())
            {
                var person = new Person { Id = Guid.NewGuid() };
                context.Persons.Add(person);
    
                var audit = new AuditPerson { AuditId = Guid.NewGuid(), Timestamp = DateTime.UtcNow, PersonId = package.Id };
    
                context.PersonAudits.Add(audit);
    
                context.SaveChangesAsync().Wait();
            }
            Console.ReadKey();
        }
    

    告诉EF PersonId是指将保存在同一个SaveChanges调用中的对象的可用替代方法是什么?

    现在,当我补充说:

    public virtual Person Person { get; set; }
    

    致AuditPerson类。但是如果没有导航属性,EF就不能解决这个问题吗?

    DB已经存在,并且具有“FKY-AudiTimePosiman”作为:

    ALTER TABLE [dbo].[AuditPerson]  WITH CHECK 
      ADD CONSTRAINT [FK_AuditPerson_Person] 
      FOREIGN KEY([PersonId])
      REFERENCES [person].[Person] ([Id])
    

    我有种感觉,我以前见过没有导航属性的情况。

    正如Steve所解释的,EF不能保证插入的顺序。 实际生产代码也发生了同样的情况(现在已修复)。显然,EF按类名排序插入(查看代码可以澄清),所以人员插入是在审核之后完成的,但是预约是在审核之前完成的,因此行为上的差异

    1 回复  |  直到 6 年前
        1
  •  2
  •   Steve Py    6 年前

    您遇到这个问题的原因是,如果没有实体之间的关系,EF不能保证插入顺序与您的代码匹配。在FK约束下,EF试图首先插入AuditPerson记录并使FK跳闸。通过指定导航属性,EF可以确定插入记录的顺序。

    HasRequired(x => x.Person)
      .WithMany()
      .HasForeignKey(x => x.PersonId);
    

    然后在设置实体时:

    context.Persons.Add(person);
    var audit = new AuditPerson { AuditId = Guid.NewGuid(), Timestamp = DateTime.UtcNow, Person = person };
    
    context.PersonAudits.Add(audit);
    context.SaveChangesAsync().Wait();
    

    另外,如果您的数据库是SQL Server,我建议使用数据库来管理使用newsequentialId()的PK,并设置EF将它们识别为标识列。或者,可以使用相同的hi/lo字节顺序生成guid,使uuid与SQL的顺序ID匹配。这些ID更适合索引。