EF Core 的 TPH 是默认继承策略,只需将基类设为 abstract、在 OnModelCreating 中配置 HasDiscriminator 及 HasValue、仅注册基类 DbSet 即可;派生类不可调用 ToTable,主键须统一,迁移后应仅生成一张含 Discriminator 列的表。

EF Core 的 TPH(Table-Per-Hierarchy)是默认继承策略,配置起来其实很直接——不需要额外声明策略,只要不显式切换成 TPT 或 TPC,它就自动生效。关键在于正确设置鉴别器(Discriminator)列,并确保所有派生类共用一张表。
明确基类为抽象类并定义公共属性
基类通常设为 abstract,包含所有子类共有的字段(如 Id、Name),避免重复建模:
- 例如
public abstract class Animal { public int Id { get; set; } public string Name { get; set; } } - 派生类只添加特有属性,比如
Cat.Lives或Dog.Breed
在 OnModelCreating 中配置 Discriminator 列
这是 TPH 的核心操作。通过 Fluent API 指定鉴别器字段名和各类型的值:
- 调用
modelBuilder.Entity().HasDiscriminator ("AnimalType") - 再用
.HasValue和("Cat") .HasValue映射具体类型("Dog") - 字段类型可以是
string、int或枚举,推荐用字符串便于调试
DbSet 只需注册基类(推荐做法)
DbContext 中只需声明基类的 DbSet,EF Core 会自动把所有派生类型的数据读写到同一张表:
public DbSetAnimals { get; set; } - 不必写
DbSet或DbSet—— 即使写了,查询时也仍走同一张表 - 表名默认取自基类 DbSet 属性名(如
Animals),不是类型名
避免常见陷阱
TPH 看似简单,但几个细节容易出错:
- 不要给派生类调用
ToTable(),否则 EF Core 会降级为 TPT 模式 - 主键必须统一(通常是基类定义的 Id),不能让子类重新配置 Key
- 如果子类有同名属性(如都叫
Code),要确保它们映射到同一列,可用HasColumnName("Code")统一指定 - 迁移生成后,检查数据库表是否只有一张,且含所有字段 + Discriminator 列
基本上就这些。TPH 不复杂但容易忽略鉴别器配置和 DbSet 声明逻辑,配对之后就能自然支持多态查询,比如 context.Animals.OfType。








