为了避免使用每个层次结构表 (TPH),我一直在研究如何在我的数据库模型中最好地实现每个具体类表 (TPC) 继承的示例。我遇到了官方文档 https://msdn.microsoft.com/en-us/data/jj591617#2.6 and 本文 https://datatellblog.wordpress.com/2015/04/12/inheritance-modelling-patterns-with-entity-framework-6-code-first/.
下面是一些带有一些简单继承的模型类。
public class BaseEntity
{
public BaseEntity()
{
ModifiedDateTime = DateTime.Now;
}
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public DateTime ModifiedDateTime { get; set; }
}
public class Person : BaseEntity
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Business : BaseEntity
{
public string Name { get; set; }
public string Location { get; set; }
}
两篇文章中的示例使用的 DbModelBuilder 配置。
modelBuilder.Entity<BaseEntity>()
.Property(c => c.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
modelBuilder.Entity<Person>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Person");
});
modelBuilder.Entity<Business>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Business");
});
应用程序成功运行,但当我返回数据库时,我发现三 (3) 个表,而不是我期望找到的两 (2) 个表。经过一些测试后,“BaseEntity”表似乎已创建但从未使用过。除了这个空的孤立表之外,一切似乎都工作得很好。
我搞乱了 DbModelBuilder 配置,最终删除了提供预期结果的“BaseEntity”配置;两 (2) 个表,每个表都具有正确的属性并且功能正常。
我做了最后一项测试,删除所有 DbModelBuilder 配置,仅包含“Person”和“Business”的两 (2) 个 DbSet 属性,然后再次测试。
public DbSet<Person> People { get; set; }
public DbSet<Business> Businesses { get; set; }
令我惊讶的是,该项目构建后,进入数据库,仅创建两个表,其中包含所有类属性,包括从“BaseEntity”类继承的属性。我可以毫无问题地执行 CRUD 操作。
运行多次测试后,我在最终测试中找不到任何问题,并且无法重现两篇文章警告的重复密钥错误。
对数据库的更改已成功提交,但出现错误
更新对象上下文时发生。 ObjectContext 可能是
处于不一致的状态。内部异常消息:AcceptChanges
无法继续,因为该对象的键值与另一个对象冲突
ObjectStateManager 中的对象。确保关键值是
在调用 AcceptChanges 之前是唯一的。
- 我很好奇为什么这些示例使用 MapInheritedProperties 属性;这是一个过时的方法吗?
- 为什么两个示例都说包含“BaseEntity”的配置属性,但包含“BaseEntity”类的 DbSet 属性或任何 DbModelBuilder 配置会导致创建未使用的表。
- 关于文章警告的唯一关键错误;我无法重现该错误,并且我已经使用主键作为数据库生成的 int 和数据库生成的 guid 进行了多次测试。有关此错误的信息是否也已过时,或者是否可以运行测试来产生所述错误?