gpt4 book ai didi

c# - Entity Framework 6 (EF6) 中每个具体类型的表 (TPC) 继承

转载 作者:太空狗 更新时间:2023-10-29 17:57:04 31 4
gpt4 key购买 nike

为了避免使用每层次结构表 (TPH),我一直在研究如何在我的数据库模型中最好地实现每个具体类表 (TPC) 继承的示例。我遇到了 official documentationthis article .

下面是一些具有一些简单继承的模型类。

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 操作。

在运行多次测试后,我在最终测试中找不到任何问题,而且我无法重现两篇文章警告过的重复 key 错误。

The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.

  1. 我很好奇为什么示例使用 MapInheritedProperties 属性;这是过时的方法吗?
  2. 为什么两个示例都说包含“BaseEntity”的配置属性,但包含“BaseEntity”类的 DbSet 属性或任何 DbModelBuilder 配置会导致创建未使用的表。
  3. 引用文章警告的唯一键错误;我无法重现该错误,并且我已经使用主键作为数据库生成的 int 和数据库生成的 guid 进行了多次测试。有关此错误的信息是否也已过时,或者是否有我可以运行以产生所述错误的测试?

最佳答案

为了让这一切变得更简单,我已经移动了强制 TablePerConcrete 开源所需的代码。其目的是允许通常仅在 Fluent Interface 中可用的功能(您必须将大量代码分散到 Db 类的 OnModelCreating 方法中)迁移到基于属性的功能。

它允许你做这样的事情:

[TablePerConcrete]
public class MySubclassTable : MyParentClassEntity

无论 EF 可能决定从您的父类/子类关系中推断出什么,都强制执行 TPC。

这里的一个有趣挑战是,有时 EF 会搞砸继承的 Id 属性,将其设置为用显式值填充而不是数据库生成。您可以通过让父类实现接口(interface) IId(它只是说:This has an Id property)来确保它不会这样做,然后用 [ForcePKId] 标记子类>.

public class MyParentClassEntity : IId
{
public int Id { get; set; }
. . .

[TablePerConcrete]
[ForcePKId]
public class MySubclassTable : MyParentClassEntity
{
// No need for PK/Id property here, it was inherited and will work as
// you intended.

开始为您处理所有这些的代码非常简单 - 只需在您的 Db 类中添加几行:

public class Db : DbContext
{
. . .
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var modelsProject = Assembly.GetExecutingAssembly();
B9DbExtender.New().Extend(modelBuilder, modelsProject);

您可以通过以下两种方式之一访问它:

  1. 通过将所有相关类复制粘贴到单个文件中的单个要点,此处:https://gist.github.com/b9chris/8efd30687d554d1ceeb3fee359c179f9

  2. 通过我们正在发布开源的 Brass9.Data 库。它有很多其他的 EF6 工具,比如数据迁移。它也更有条理,如您通常所期望的那样将类分解为单独的文件:https://github.com/b9chris/Brass9.Data

关于c# - Entity Framework 6 (EF6) 中每个具体类型的表 (TPC) 继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32596289/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com