領域模型中常見繼承體系 (如 Vehicle ← Car/Truck),關係型資料表無原生繼承概念。如何將「是一種」關係映射為資料表結構,直接影響**查詢效能、資料冗余、維護成本**。
結構:一張表對應整個繼承樹,所有子類欄位合併,加 Discriminator 欄位區分型別。
CREATE TABLE Vehicle (
Id INT PK,
VehicleType VARCHAR(20), -- 'Car' / 'Truck'
Engine VARCHAR(50),
Wheel INT,
Container VARCHAR(50), -- Truck 專用
Acoustics VARCHAR(50) -- Car 專用
);
| 優點 | 缺點 |
|---|---|
| 查詢最快 (單表、無 JOIN) CRUD 簡單 Schema 變更僅改一張表 | 稀疏欄位多 → 空間浪費、頁面分裂 NOT NULL 約束難加 (子類必填欄位在父類可為 NULL) 大型繼承樹欄位爆炸 |
結構:每個**具體類別**一張表,包含父類所有欄位 (複製)。
CREATE TABLE Car (Id PK, Engine, Wheel, Acoustics);
CREATE TABLE Truck (Id PK, Engine, Wheel, Container);
| 優點 | 缺點 |
|---|---|
| 無空值浪費 各表欄位精簡、約束完整 單一實體查詢極快 | **多型查詢需 UNION ALL** (SELECT * FROM Car UNION ALL SELECT * FROM Truck) 主鍵跨表唯一性難保證 父類欄位變更需同步修改所有子表 |
結構:父類一張表,每個子類一張表,**主鍵同時為外鍵**關聯父表。
CREATE TABLE Vehicle (Id PK, Engine, Wheel);
CREATE TABLE Car (Id PK FK REFERENCES Vehicle, Acoustics);
CREATE TABLE Truck (Id PK FK REFERENCES Vehicle, Container);
| 優點 | 缺點 |
|---|---|
| 正規化程度高、無冗余 支援多型查詢 (LEFT JOIN) 父類欄位單一維護 | 查詢需 JOIN (效能較慢) 插入/刪除需跨表事務 深層繼承 JOIN 鏈長 |
| 維度 | 單表 | 具體類別表 | 類別表 |
|---|---|---|---|
| 空間效率 | 低 (稀疏) | 高 | 高 |
| 多型查詢 | 極快 | 慢 (UNION) | 中 (JOIN) |
| 單一實體查詢 | 快 | 最快 | 中 (JOIN) |
| Schema 變更 | 易 | 難 (多表同步) | 中 |
| 適用場景 | 淺繼承、欄位少、讀多寫少 | 深繼承、子類差異大、少多型查詢 | 企業級、正規化優先、多型查詢常見 |
ToTable + HasBaseType),TPC 需手動映射。<union-subclass> (TPC)、<joined-subclass> (TPT)、單表 (預設)。大型系統常**混合使用**:核心領域 (如 Party/Account) 用類別表保證正規化;邊緣功能 (如 Log/Event) 用單表換效能。EF Core 6+ 同一 DbContext 可混合 TPH/TPT。
沒有銀彈,**單表換空間換查詢速度,類別表換正規化換 JOIN 開銷,具體類別表換隔離換 UNION 複雜度**。架構師應依**查詢模式、資料量、團隊熟悉度、演進策略**綜合決策,並在專案初期以原型驗證效能。