TPH vs TPT vs TPC
前言
Entity Framework 支援三種繼承的Model設計,Table Per Hierarchy(TPH)、Table Per Type(TPT)、Table Per Concrete Class(TPC),每一種設計各有其優缺點,而今天就來介紹這三者的差異。
Table Per Hierarchy(TPH)
Code First預設就是採用TPH策略,mapping 繼承的型別(子類別的欄位)至單一的資料表,該資料表會有一個Discriminator column來區分是哪一個子類別。
例如以下範例:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Teacher : Person
{
public string Position { get; set; }
}
會產生這樣的Table
而產生的Discriminator會來記錄是用Person新增的資料還是Teacher新增的資料
自訂Discriminator
預設的Discriminator如果不喜歡,可用Fluent API自訂該欄位型別或者欄位名稱
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasDiscriminator<bool>("IsTeacher")
.HasValue<Person>(false)
.HasValue<Teacher>(true);
}
重新產生後的欄位
Table Per Type(TPT)
TPT只會儲存base class 的properties至單一table,而子類別的欄位會存在不同的table,並且用foreign key關聯。
設定方法則是將子類別指定table名稱就可以了
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
[Table("Teacher")]
public class Teacher : Person
{
public string Position { get; set; }
}
或者使用Fluent API的方式
modelBuilder.Entity<Person>()
.Map<Teacher>(m =>
{
m.ToTable("Teacher");
});
產生的Table
Table Per Concrete Class(TPC)
TPC並沒有base class的table,每一個子類別所產生的table都會包含base class的欄位,這個適合用在不同table中紀錄歷史資料。
使用Fluent API設定。 這邊只要是使用MapInheritedProperties()來告訴Code First要將父類別的Properites產生到子類別的table欄位上。
modelBuilder.Entity<Person>().Map(m =>
{
m.ToTable("Person");
}).Map<Teacher>(m =>
{
m.ToTable("Teacher");
m.MapInheritedProperties();
});
產生的資料表
注意:TPC並不會建立foreign key關聯
小結
這三種方式各有優存點,詳細說明,可參考 How to choose an Inheritance Strategy。
一天一分享,身體好健康。
該追究的不是過去的原因,而是現在的目的。