实体框架TPC:为什么BaseEntity Id必须是Guid类型?

时间:2015-09-30 06:09:03

标签: c# entity-framework

我遇到了ObjectContext不一致状态异常:

  

数据库的更改已成功提交,但出现错误   更新对象上下文时发生。 ObjectContext可能是   处于不一致的状态。内部异常消息:AcceptChanges   无法继续,因为对象的键值与另一个键冲突   ObjectStateManager中的对象。确保键值是   在调用AcceptChanges之前是唯一的。

这似乎发生在我的基本实体(自使用TPC以来的抽象)具有

之后
public int Id { get; set;}

配置为数据库生成的主键:

// Base Entity
modelBuilder.Entity<BaseEntityObject>().HasKey(t => t.Id);
modelBuilder.Entity<BaseEntityObject>().Property(t => t.Id).
    HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

和派生实体也继承了这一点并尝试将其用作主键。

当您实例化两种不同类型的派生条目时,将它们添加到DbContext,然后尝试SaveChanges(),触发异常。但是,当Id字段从int:

更改为Guid时
public Guid Id { get; set;}

不再抛出此异常。

  1. 有人可以解释为什么当Id属性类型为int时会发生这种情况吗?

  2. 有解决方法吗?让每个派生实体拥有Guid PK似乎有点浪费。

1 个答案:

答案 0 :(得分:1)

我认为您面临的问题是因为您正在为基本实体配置主键和标识,但您应该为派生实体执行相同操作,因为通常我们不会将BaseEntityObject存储在数据库中。

您需要执行以下操作:

modelBuilder.Entity<DerivedEntityObject1>().HasKey(t => t.Id);
modelBuilder.Entity<DerivedEntityObject1>().Property(t => t.Id).
    HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

modelBuilder.Entity<DerivedEntityObject2>().HasKey(t => t.Id);
modelBuilder.Entity<DerivedEntityObject2>().Property(t => t.Id).
    HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

<强>更新

  1. 创建基本实体类型配置并在实体配置中继承。

    public class TestContext : DbContext
    {
        public DbSet<TestEntity1> TestEntities1 { get; set; }
        public DbSet<TestEntity2> TestEntities2 { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new TestEntity1Configuration());
            modelBuilder.Configurations.Add(new TestEntity2Configuration());
    
            base.OnModelCreating(modelBuilder);
        }
    }
    
    public class BaseEntityConfiguration<T> : EntityTypeConfiguration<T> where T : BaseEntity
    {
        public BaseEntityConfiguration()
        {
            HasKey(d => d.Id).Property(d => d.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
        }
    }
    
    public class TestEntity1Configuration : BaseEntityConfiguration<TestEntity1> { 
        //your configuration here.
    }
    
    public class TestEntity2Configuration : BaseEntityConfiguration<TestEntity2> {
        //your configuration here.
    }
    
  2. 智能方法是使用如下所示的数据注释:

    public class BaseEntity
    {
        [Key]
        [DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
    }
    
    public class TestEntity1 : BaseEntity
    {
        public string Name { get; set; }
    }
    
    public class TestEntity2 : BaseEntity
    {
        public string Name2 { get; set; }
    }