EF#3. Entity & Inheritance

EF#3. Entity & Inheritance — ORM 中的繼承對應策略

問題與答案 (FAQ)

Q&A 類別 A: 概念理解類

Q1: 什麼是物件導向中的繼承?

  • A簡: 繼承是子類別自動擁有父類別的資料欄位與方法,形成「是某種(Is-A)」的階層關係。
  • A詳: 在 OOP 中,繼承讓子類別繼承父類別的資料成員與行為,使共用邏輯能集中於父類別,子類別再延伸或覆寫。它支撐多型、重用與抽象等核心特性。資料層面上,子類別等同於「擁有父類別定義的所有欄位」,因此在映射到資料庫時,需決定如何保存父子欄位與查詢策略,這正是 ORM 需解決的關鍵。
  • 難度: 初級
  • 學習階段: 基礎
  • 關聯概念: A-Q2, A-Q3, A-Q10, B-Q1

Q2: 為什麼繼承是 OOP 的核心?

  • A簡: 它讓抽象與重用成為可能,促成多型與可擴展設計,是多數 OOP 特色的基礎。
  • A詳: 繼承將共同的資料與行為集中在父類別,降低重複與維護成本。多型使相同介面能對應不同子類別的行為,擴展性與替換性隨之提升。少了繼承,OOP 難以達到抽象與重用的優勢。因此當物件要持久化到 RDBMS 時,如何保存與重建繼承階層,成了 ORM 不可迴避的議題。
  • 難度: 初級
  • 學習階段: 基礎
  • 關聯概念: A-Q1, A-Q3, A-Q10

Q3: 什麼是 ORM?與繼承有何關係?

  • A簡: ORM 將物件模型對應到關聯式資料庫,需處理類別、屬性、關聯與繼承的映射。
  • A詳: ORM(Object-Relational Mapping)負責把物件的結構與關聯,轉換為 RDBMS 的資料表、欄位與關聯。因 RDBMS 並不具物件導向概念,特別不支援繼承,ORM 必須選擇合適策略保存父子共用與差異欄位,並能有效率查詢、插入、更新與刪除。常見繼承映射策略有 TPH、TPT、TPC,各有優缺點與適用情境。
  • 難度: 初級
  • 學習階段: 基礎
  • 關聯概念: A-Q4, A-Q7, A-Q8, A-Q9, A-Q10

Q4: RDBMS 與 OOP 的差異是什麼?為何需要映射?

  • A簡: RDBMS 缺乏物件與繼承概念;需藉由映射策略將物件層的繼承對應為資料表設計。
  • A詳: OOP 操作物件、繼承、多型;RDBMS 則以表、列、欄與關聯為中心,沒有原生的繼承。要把物件持久化,必須設計對應方式讓父子欄位能被還原與查詢。映射策略決定了資料正規化程度、查詢成本、約束嚴謹性與架構彈性,是設計成功與否的關鍵。
  • 難度: 初級
  • 學習階段: 基礎
  • 關聯概念: A-Q3, A-Q7, A-Q8, A-Q9

Q5: 什麼是 virtual table?在 OOP 中扮演什麼角色?

  • A簡: virtual table(虛表)支援虛擬方法調度與繼承,讓子類別能覆寫父類別的方法。
  • A詳: 在如 C++ 的實作中,每個型別維護一張虛表,記錄可被動態呼叫的方法入口。子類別繼承父類別時,會攜帶父類別欄位與虛表並可覆寫條目。雖然 DB 沒有虛表,但可將「虛表定義像 table schema」「物件 instance 像資料列」做直覺類比,幫助理解資料層如何承載繼承。
  • 難度: 中級
  • 學習階段: 基礎
  • 關聯概念: A-Q6, A-Q1, B-Q1

Q6: virtual table 與資料庫 table schema 的類比是什麼?

  • A簡: 虛表像型別的「方法與欄位結構」,類比為資料表的 schema;物件像一筆資料列。
  • A詳: OOP 物件依據虛表決定可用方法與欄位佈局;RDBMS 的表 schema 決定列的欄位結構。當把物件持久化時,可類比為「以 schema 定義資料形狀」,以便在載入時還原成對應類別。此類比有助思考「子類別擁有父類別欄位」如何在表設計上被落實。
  • 難度: 中級
  • 學習階段: 基礎
  • 關聯概念: A-Q5, A-Q7, A-Q8, A-Q9

Q7: 什麼是 Table per Hierarchy (TPH)?

  • A簡: 以一張表承載整個繼承階層,欄位為各子類別欄位聯集,常以型別欄位區分行別。
  • A詳: TPH 把父類別與所有子類別資料放同一表,表欄位是所有子類別欄位的總和。未用到的欄位通常為空值,並透過型別標記欄位分辨行所屬的子類別。它是最簡單、查詢整體最方便的方式,但當資料量大時表會臃腫,且難以對特定子類別欄位施加嚴格約束。
  • 難度: 初級
  • 學習階段: 核心
  • 關聯概念: A-Q10, A-Q11, A-Q12, B-Q1

Q8: 什麼是 Table per Type (TPT)?

  • A簡: 父、子類別各有各的表,子表以外鍵(同時為主鍵)指向父表,查詢需 join 聚合。
  • A詳: TPT 依類別切表:父類別在基底表,子類別表只存該子類別新增欄位,並用 PK=FK 指向父表同一主鍵。好處是正規化、約束可精準施加,易於個別類別調整;缺點是繼承層級深時,單筆查詢需多層 join,影響效能與複雜度。
  • 難度: 初級
  • 學習階段: 核心
  • 關聯概念: A-Q10, A-Q13, A-Q14, B-Q2

Q9: 什麼是 Table per Concrete Type (TPC)?

  • A簡: 每個具體子類別各自一張完整表,重複父類別欄位;查詢基底型別需合併多表。
  • A詳: TPC 為每個具體類別建立獨立表,包含父類別欄位與自身欄位,避免 join 的成本,並可為各類別定制嚴謹約束。代價是父類別欄位重複於多表,造成調整成本增高,且跨子類別的整體查詢需以 union/合併實作,並不直覺。
  • 難度: 初級
  • 學習階段: 核心
  • 關聯概念: A-Q10, A-Q15, A-Q16, B-Q3

Q10: TPH、TPT、TPC 的差異為何?

  • A簡: TPH 一表容納、查詢簡易但約束弱;TPT 正規化強但多層 join;TPC 重複欄位、合併查詢較難。
  • A詳: 三者取捨在於正規化、查詢成本與約束能力。TPH 用一表與型別標記,易查全階層但欄位多且約束難嚴格;TPT 父子分表以 PK=FK 聯結,模型清晰、約束嚴謹但 join 增多;TPC 子類各表完整定義,映射直覺且可嚴格約束,代價是欄位重複、全體查詢需 union。
  • 難度: 初級
  • 學習階段: 核心
  • 關聯概念: A-Q7, A-Q8, A-Q9

Q11: 何時適合使用 TPH?

  • A簡: 階層簡單、同系實體數量不大、常需一次查全體、欄位調整頻繁時適合。
  • A詳: TPH 的一表結構讓「跨子類一次查詢」最容易,維護變更也簡化;對於階層不深、資料量適中且對子類別欄位約束要求不高的場景尤其合適。若同系實體量級小,單表膨脹與稀疏欄位的影響可接受,帶來最快的開發與查詢整體性。
  • 難度: 初級
  • 學習階段: 核心
  • 關聯概念: A-Q7, A-Q12, B-Q1, D-Q1

Q12: 何時不適合使用 TPH?

  • A簡: 實體數量龐大、需嚴格表層約束、欄位稀疏嚴重時,TPH 效能與一致性不足。
  • A詳: 單表承載整個階層對大數量場景易引發索引與 I/O 壓力;子類別特有欄位在 TPH 難以設計 NOT NULL 或細緻約束;大量空值造成儲存與統計不便。此時應評估 TPT(強約束、正規化)或 TPC(避免 join)以平衡效能與資料品質。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: A-Q11, B-Q1, D-Q1, D-Q2

Q13: 何時適合使用 TPT?

  • A簡: 需嚴謹約束、類別變動獨立、仍常要跨階層查詢,且可接受 join 成本時。
  • A詳: TPT 保持正規化,能對各子類別欄位設嚴格約束,父子關聯一目了然。每個類別的表局部調整容易,影響面小。若查詢模式常橫跨階層,且資料量或索引可控,藉由少量 join 可換得高資料品質,是穩健選項。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: A-Q8, A-Q14, B-Q2, D-Q3

Q14: 何時不適合使用 TPT?

  • A簡: 階層很深或高頻單筆查詢時,多層 join 成本高、維運與調校複雜。
  • A詳: 當繼承層級擴展,單筆載入需連動多表 join,查詢計畫與索引調整成本提升,ORM 也易產生複雜 SQL。若效能瓶頸明顯,且查詢多為單一子類別,應改以 TPC 或適度扁平化,降低 join 依賴。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: A-Q13, B-Q2, D-Q3

Q15: 何時適合使用 TPC?

  • A簡: 想避免 join、需為各子類別設嚴格約束,且可接受欄位重複與合併查詢難度時。
  • A詳: TPC 子類各表自足,存取單一子類別時最直接,約束可依表量身設定,映射直覺。適合單子類別存取為主、整體查詢較少的場景。若能用視圖或應用層統一整合跨表查詢,TPC 兼具彈性與效能。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: A-Q9, A-Q16, B-Q3, D-Q4

Q16: 何時不適合使用 TPC?

  • A簡: 常需跨所有子類別查詢或父類別欄位常變動時,TPC 維護與查詢成本高。
  • A詳: 因父類別欄位重複散落多表,任何父類別變更都需廣泛同步,風險與工作量大。若報表與分析需頻繁彙總全體,TPC 的 UNION/整合負擔明顯,易造成錯誤與效能問題。此時傾向 TPH 或 TPT。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: A-Q15, B-Q3, D-Q4, D-Q5

Q17: 什麼是正規化與反正規化?對繼承映射的意義?

  • A簡: 正規化減少重複、強一致;反正規化容許重複換取效能。映射策略在兩者間取捨。
  • A詳: 正規化(如 3NF)拆分資料以消除重複並維持一致性;反正規化則為了讀取效率或簡化查詢而容許重複。TPT 偏正規化;TPH 以一表簡化;TPC 偏反正規化以換取讀取單一子類別的效率。選型需根據資料品質與效能需求平衡。
  • 難度: 初級
  • 學習階段: 基礎
  • 關聯概念: A-Q10, B-Q9

Q18: 為何 TPH 被稱為最簡單的實作方式?

  • A簡: 單一表、簡單查詢與維護,變更集中;但以降低約束嚴謹性為代價。
  • A詳: TPH 僅需建立一表並在設計上涵蓋全部欄位,查詢全體或多型最直覺,新增子類多為加欄位與型別標記,維護集中。其限制是無法針對特定子類欄位施嚴格約束與大表效能問題,屬快速啟動與簡單階層的優選。
  • 難度: 初級
  • 學習階段: 基礎
  • 關聯概念: A-Q7, A-Q11, A-Q12

Q19: 為何在 TPT 中每個類別變動都容易?

  • A簡: 因父子分表、關注點分離,修改某子類欄位不影響其他類別表。
  • A詳: TPT 的表設計對應類別邊界:子類別新增或修改僅影響自己的表與與父表的鍵關係,不需變動其他子類的表。這降低了變更牽連與風險,亦方便設定針對性的約束與索引。缺點是查詢跨階層時依賴 join。
  • 難度: 初級
  • 學習階段: 核心
  • 關聯概念: A-Q8, A-Q13, B-Q2

Q20: EF 與 NH 對三種策略的命名對應?

  • A簡: EF: TPH/TPT/TPC;NH: Table per class hierarchy / per subclass / per concrete class。
  • A詳: 兩大 ORM 都支持三種路線,但命名略不同。EF 用 Table per Hierarchy、Table per Type、Table per Concrete Type;NHibernate 對應為 Table per class hierarchy、Table per subclass、Table per concrete class。理解同名異稱能避免溝通誤會並促進跨工具遷移。
  • 難度: 初級
  • 學習階段: 基礎
  • 關聯概念: A-Q7, A-Q8, A-Q9, B-Q10, D-Q9

Q&A 類別 B: 技術原理類

Q1: TPH 如何運作?

  • A簡: 以單一表存父子聯集欄位,行內用型別標記區分子類別,未用欄位留空。
  • A詳: 技術原理說明:TPH 以同一表保存所有類別資料,欄位為聯集。核心組件包含「型別標記欄位」與覆蓋全部需求的欄位集合。關鍵步驟:插入時寫入型別值與對應欄位;查詢時以型別值決定實體型別;更新僅觸及該型別相關欄位。優點是單表與單查詢;限制在約束與大表效能。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: A-Q7, A-Q11, A-Q12, B-Q4, B-Q5

Q2: TPT 的執行流程為何?

  • A簡: 父子分表,子表以 PK=FK 指向父表;查詢需 join 聚合父子欄位。
  • A詳: 技術原理說明:TPT 以一對一(共享主鍵)的關聯連結父與子。核心組件:基底表、子表、共享鍵與外鍵約束。關鍵步驟:插入先寫父表,再寫子表;查詢以主鍵 join 取回完整資料;更新分別更新對應表;刪除先刪子再刪父。優勢是正規化與約束嚴謹;劣勢是 join 成本。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: A-Q8, A-Q13, A-Q14, B-Q5, B-Q6

Q3: TPC 的機制是什麼?

  • A簡: 子類各自完整表,重複父欄位;聚合成基底型別時需合併多表結果。
  • A詳: 技術原理說明:每個具體子類有獨立 schema,避免父子 join。核心組件:各子類表、相同語意的共用欄位名稱/型別。關鍵步驟:插入/查詢/更新僅針對該子表;若查詢基底型別,需 union 或在 ORM 層聚合不同來源。優點是單表操作快且可嚴格約束;缺點是欄位同步與跨子類查詢複雜。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: A-Q9, A-Q15, A-Q16, B-Q4, B-Q5

Q4: 以單一查詢取得所有子類別物件在各策略如何達成?

  • A簡: TPH/TPT 較直覺;TPC 需 union 合併各子類表結果才行。
  • A詳: 技術原理:TPH 天生一表,可直接 where 型別或不分型別掃描;TPT 可對父表 join 左右子表或以視圖包裝;TPC 因多表分散,需 union all 將各子表映射到共同欄位集合。流程:設計統一欄位別名、建立視圖/查詢模板。核心組件:型別標記、join 邏輯或 union 視圖。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: B-Q1, B-Q2, B-Q3, D-Q4

Q5: 各策略的插入流程差異?

  • A簡: TPH 單表插入;TPT 先父後子;TPC 直接插入對應子表。
  • A詳: 原理與流程:TPH 只需在單表寫入型別與欄位;TPT 需事先取得主鍵(或用同鍵策略),插入父表再插子表以完成 PK=FK;TPC 只觸及子表,不依賴父表。核心組件:鍵產生策略、事務一致性。TPH 最簡,TPT 步驟最多,TPC 局部最直接。
  • 難度: 初級
  • 學習階段: 核心
  • 關聯概念: B-Q1, B-Q2, B-Q3

Q6: 各策略的更新與刪除流程差異?

  • A簡: TPH 單表更新/刪除;TPT 分別更新多表且刪除需先子後父;TPC 僅觸及子表。
  • A詳: 流程:TPH 直接以鍵定位單表操作;TPT 需確保子表更新與父表一致,刪除先移除子表記錄再刪父表避免 FK 衝突;TPC 僅更新/刪除對應子表。核心組件:交易管理、外鍵約束、觸發程序(若採用)。考量:TPT 操作步驟多但一致性強,TPC 簡潔但需防重複欄位一致性。
  • 難度: 初級
  • 學習階段: 核心
  • 關聯概念: B-Q2, B-Q3, D-Q5, D-Q7

Q7: TPT 的鍵與關聯應如何設計?

  • A簡: 採共享主鍵模型,子表主鍵同時為 FK 指向父表主鍵,建立一對一嚴格鏈結。
  • A詳: 原理:共享主鍵確保一個父記錄對應零或一個子記錄。步驟:父表定義 PK;子表以相同型別與值為 PK,並設為 FK 參照父表;設唯一與必要約束;索引主鍵以優化 join。核心組件:PK、FK、唯一/檢查約束。此設計清楚表達繼承關係且防止孤兒資料。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: A-Q8, B-Q2, C-Q3, C-Q7

Q8: 欄位調整在三種策略中的影響與流程?

  • A簡: TPH 影響單表最小;TPT 影響父或該子表;TPC 需同步所有子表。
  • A詳: 流程:TPH 在單表新增/修改欄位即可;TPT 若是父欄位變動影響所有子類的 join 與 ORM 映射,但實際更動表數較少;TPC 父欄位等價於多表重複,需批次同步結構與資料修正。核心組件:遷移腳本、自動化檢核、回滾計畫。
  • 難度: 中級
  • 學習階段: 進階
  • 關聯概念: A-Q10, A-Q18, A-Q19, D-Q5

Q9: 以正規化觀點解讀三種策略的技術取捨?

  • A簡: TPT 最正規化;TPH 折衷以一表簡化;TPC 為讀取效率反正規化。
  • A詳: 原理:正規化降低重複和異常,反正規化換取讀效與簡化查詢。TPT 嚴謹一致但 join 成本高;TPH 集中簡化但欄位稀疏與約束受限;TPC 重複欄位換更快的單表存取與子類別約束。選型取決於一致性要求、查詢模式與資料量。
  • 難度: 初級
  • 學習階段: 核心
  • 關聯概念: A-Q17, A-Q10, D-Q6

Q10: EF/NH 如何在概念層支持三種策略?

  • A簡: 兩者皆提供三種繼承映射概念與設定方式,名稱略異但原理一致。
  • A詳: 原理:ORM 在對應層提供將類別階層映射到表結構的配置。關鍵:TPH 設型別標記與欄位聯集;TPT 設父子對應與共享主鍵關聯;TPC 設每子類對應其表與共同欄位。核心組件:映射描述(XML/註解/流暢 API)、鍵與約束、查詢合成。命名差異見 A-Q20。
  • 難度: 初級
  • 學習階段: 核心
  • 關聯概念: A-Q20, B-Q1, B-Q2, B-Q3

Q&A 類別 C: 實作應用類(10題)

Q1: 如何設計一個 TPH 的資料表架構?

  • A簡: 建一張覆蓋父子欄位的表,加一個型別標記欄位,未用欄位允許空值。
  • A詳: 實作步驟:1) 列出父與各子類欄位的聯集;2) 建單一表含所有欄位;3) 增加 Type 欄位標記子類;4) 為共用欄位設適當約束。程式碼片段(SQL):CREATE TABLE Entities(Id PK, Type, BaseCol…, SubACol NULL, SubBCol NULL, …)。注意事項:型別標記值需穩定;索引需根據查詢模式;避免過度稀疏欄位。
  • 難度: 初級
  • 學習階段: 基礎
  • 關聯概念: B-Q1, C-Q2, D-Q2

Q2: 如何為 TPH 建立辨識子類別的欄位?

  • A簡: 新增 Type 欄位並定義可選值,配合檢查約束限制合法型別。
  • A詳: 實作步驟:1) 新增 Type(如 nvarchar 或小整數);2) 設 CHECK 約束限制合法型別值;3) 為 Type 建索引以利篩選。SQL 片段:ALTER TABLE Entities ADD Type nvarchar(50) NOT NULL; ALTER TABLE Entities ADD CONSTRAINT CK_Entities_Type CHECK (Type IN (‘A’,’B’,’C’)); 注意事項:維護列舉與程式對應、避免魔術字串。
  • 難度: 初級
  • 學習階段: 核心
  • 關聯概念: C-Q1, D-Q2

Q3: 如何設計一個 TPT 的資料表與鍵?

  • A簡: 建父表與多子表,子表主鍵同時作為指向父表的外鍵(共享主鍵)。
  • A詳: 步驟:1) 建 Parent(Id PK, BaseCols);2) 建 ChildA(Id PK/FK→Parent.Id, ACols);3) 建 ChildB(…);4) 設外鍵 ON DELETE CASCADE 視需求。SQL 片段:CREATE TABLE Parent(Id PK,…); CREATE TABLE ChildA(Id PK, FOREIGN KEY(Id) REFERENCES Parent(Id), …)。注意:為 join 常用欄位建立索引;約束依子表需求設置。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: B-Q2, C-Q4, C-Q7

Q4: 如何在 TPT 中撰寫查詢以載入子類別資料?

  • A簡: 以主鍵將父表 join 子表,選取父子欄位組合映射到子類別。
  • A詳: 步驟:1) 針對特定子類別:SELECT p…, a… FROM Parent p JOIN ChildA a ON p.Id=a.Id WHERE …;2) 針對多型查詢:以 LEFT JOIN 多個子表並以子表非空判斷類型。注意:只取需要欄位;為常用條件加索引;避免過多 LEFT JOIN 造成計畫不穩。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: B-Q2, B-Q4, D-Q3

Q5: 如何設計一個 TPC 的資料表集合?

  • A簡: 為每個具體子類別建完整表,重複父欄位並一致命名與型別。
  • A詳: 步驟:1) 定義共用欄位規範(名稱/型別/意義);2) 為 ChildA 建表包含共用+專屬欄位;3) 為 ChildB 類似設計;4) 規範主鍵與索引策略。SQL 片段:CREATE TABLE ChildA(Id PK, BaseCol1…, ACol…); CREATE TABLE ChildB(…); 注意:維持共用欄位一致;以檢核腳本比對結構。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: B-Q3, C-Q6, D-Q5, D-Q7

Q6: 如何用 SQL UNION 支援 TPC 的基底型別查詢?

  • A簡: 為各子表選出相同欄位並以 UNION ALL 合併成基底結果集或視圖。
  • A詳: 步驟:1) 將共用欄位對齊別名;2) 為每子表加上常數型別欄位;3) 撰寫 UNION ALL;4) 視需求建立視圖。SQL 片段:SELECT Id,Base1,…,’A’ AS Type FROM ChildA UNION ALL SELECT Id,Base1,…,’B’ FROM ChildB。注意:避免 UNION(去重)以節省成本;視圖上可加索引(視 DBMS)。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: B-Q4, D-Q4, D-Q6

Q7: 如何為 TPT 加入嚴格的表約束?

  • A簡: 針對子表欄位設 NOT NULL、CHECK、外鍵與唯一約束,確保資料品質。
  • A詳: 步驟:1) 在子表為必填欄位設 NOT NULL;2) 建 CHECK 約束限制值域;3) 為父子鍵設外鍵且適當 ON DELETE/UPDATE 規則;4) 對唯一性需求建 UNIQUE。SQL:ALTER TABLE ChildA ADD CONSTRAINT CK_ChildA_Status CHECK (Status IN (…))。最佳實踐:盡量用 DB 約束而非僅靠應用程式驗證。
  • 難度: 中級
  • 學習階段: 進階
  • 關聯概念: A-Q13, B-Q2, C-Q3

Q8: 如何在父類別新增欄位時同步 TPC 的所有表?

  • A簡: 建立結構遷移腳本批次更新所有子表,且加入自動檢核避免遺漏。
  • A詳: 步驟:1) 撰寫多表 ALTER TABLE 腳本;2) 以資訊綱要檢查各表欄位一致性;3) 對現有資料填入預設值;4) 加入部署自動檢核與回滾計畫。SQL 片段:ALTER TABLE ChildA ADD BaseNew …; ALTER TABLE ChildB ADD BaseNew …。最佳實踐:集中共用欄位規格文件,建立對齊工具。
  • 難度: 中級
  • 學習階段: 進階
  • 關聯概念: B-Q8, C-Q5, D-Q5

Q9: 如何選擇三種策略的實作清單與決策步驟?

  • A簡: 先明確查詢模式與一致性需求,再依資料量與約束挑選 TPH/TPT/TPC。
  • A詳: 步驟:1) 盤點查詢:單子類 vs 全體、多型需求強弱;2) 評估資料量與成長;3) 評估約束嚴謹性與異常成本;4) 選型:簡單少量→TPH,嚴謹與跨層查詢→TPT,單子類效能與約束→TPC;5) 預留轉換路徑。注意:以原型驗證關鍵查詢效能。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: A-Q11, A-Q13, A-Q15, D-Q10

Q10: 如何將 EF/NH 設定與資料表設計對齊?

  • A簡: 依策略設定類別到表、鍵與關聯;確保映射與表結構一致並以測試驗證。
  • A詳: 步驟:1) 依 TPH/TPT/TPC 設計表;2) 在 ORM 中對應類別至表、鍵與欄位(TPH 設型別辨識、TPT 設父子一對一、TPC 為各子類對應其表);3) 以整合測試驗證 CRUD 與多型查詢;4) 監控生成 SQL。注意:不同 ORM 命名略異,對照 A-Q20。
  • 難度: 中級
  • 學習階段: 進階
  • 關聯概念: B-Q10, C-Q1, C-Q3, C-Q5

Q&A 類別 D: 問題解決類(10題)

Q1: TPH 表過大導致查詢效能差,怎麼辦?

  • A簡: 針對型別與常用條件建索引、垂直切分或改為 TPT/TPC,並優化只取必要欄位。
  • A詳: 症狀:單表行數龐大、查詢掃描多、I/O 與鎖競爭高。原因:欄位稀疏與聯集欄位造成寬表、索引缺失。解法:1) 建 Type 與關鍵欄位索引;2) 僅選取必要欄位;3) 熱資料拆分或以視圖隔離;4) 重新選型為 TPT/TPC。預防:在設計期估算資料量,定期審視索引與查詢計畫。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: A-Q11, A-Q12, B-Q1, C-Q1

Q2: TPH 無法對子類別做 NOT NULL 約束,如何處理?

  • A簡: 以型別欄位搭配 CHECK 約束模擬條件必填,或改用 TPT/TPC 強化約束。
  • A詳: 症狀:不同子類別必填欄位在同一表中不得為空卻難以直接約束。原因:TPH 欄位共享且對他型別為空。解法:1) 建 CHECK(Type=’A’→ACols 非空 等);2) 在應用層加驗證;3) 若約束複雜,改 TPT/TPC。預防:設計期確認欄位必填差異,評估策略適配性。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: B-Q1, C-Q2, A-Q12

Q3: TPT 層級深導致多層 JOIN 變慢,如何優化?

  • A簡: 精簡投影、適當索引、避免跨層即時查詢,必要時以視圖/快取或調整策略。
  • A詳: 症狀:查單一實體需多次 join,延遲高。原因:層級深、索引不足。解法:1) 僅取需要欄位;2) 為 join 鍵與篩選欄位加索引;3) 使用讀模型/物化視圖;4) 將熱路徑改為 TPC 或局部扁平化。預防:限制階層深度、針對關鍵查詢做原型測試。
  • 難度: 中級
  • 學習階段: 進階
  • 關聯概念: A-Q14, B-Q2, C-Q4

Q4: TPC 難以用單一查詢查出所有子類別,怎麼解?

  • A簡: 以 UNION ALL 建視圖或在應用層聚合,統一欄位對齊與型別標記。
  • A詳: 症狀:報表或多型查詢需跨所有子類別卻無共表。原因:資料分散多表。解法:1) 寫 UNION ALL 產出基底投影,建視圖重用;2) 在 ORM 層定義多資料來源聚合;3) 僅在需要時彙總。預防:早期辨識整體查詢需求,慎選 TPC 或預建視圖。
  • 難度: 中級
  • 學習階段: 核心
  • 關聯概念: A-Q16, B-Q4, C-Q6

Q5: 父類別欄位調整牽動 TPC 多表,如何降低風險?

  • A簡: 自動化遷移、結構一致性檢查、灰度釋出,並完善回滾機制。
  • A詳: 症狀:一次變更需要修改多個表且易漏改。原因:TPC 重複父欄位。解法:1) 以腳本批次同步;2) 用資訊綱要比對工具檢核;3) 逐步部署與資料回填;4) 測試覆蓋 CRUD 與查詢。預防:維持欄位規格單一真相、建立結構漂移監控。
  • 難度: 中級
  • 學習階段: 進階
  • 關聯概念: B-Q8, C-Q5, C-Q8

Q6: 需要跨所有子類別做報表,該選哪種策略或怎麼設計?

  • A簡: 優先 TPH 或 TPT;若 TPC 已採用,建立 UNION 視圖或 ETL 到報表表。
  • A詳: 症狀:多型報表開發成本高。原因:TPC 跨表彙總困難或 TPT join 太多。解法:1) TPH 一表最直覺;2) TPT 用左/內連接與視圖;3) TPC 建 UNION ALL 視圖或定期 ETL 彙總表。預防:需求初期即納入報表模式,策略選型以查詢為先。
  • 難度: 初級
  • 學習階段: 核心
  • 關聯概念: A-Q10, B-Q4, C-Q6

Q7: 資料不一致出現在 TPC 的重複欄位,如何診斷與修復?

  • A簡: 比對各表共用欄位差異、訂正來源、補齊同步流程並加一致性檢核。
  • A詳: 症狀:相同實體語意在不同子表有不同值。原因:更新流程不一致、缺乏規範。解法:1) 撰寫差異查詢找出不一致;2) 以權威來源表為準回補;3) 強化寫入路徑與交易規則;4) 建定期一致性檢核。預防:建立欄位規格、使用檢核腳本與 CI 驗證。
  • 難度: 中級
  • 學習階段: 進階
  • 關聯概念: C-Q5, C-Q8, B-Q3

Q8: 專案初期不確定繼承階層深度,該如何規劃映射?

  • A簡: 以 TPH 快速啟動並監控資料量與約束需求,必要時預留轉換到 TPT/TPC 的路徑。
  • A詳: 症狀:需求未明、變動大。原因:未知的類別增長與查詢模式。解法:1) 原型用 TPH 降低門檻;2) 設計抽象映射層,避免應用綁死;3) 建資料量與查詢監測;4) 規劃轉換計畫與資料遷移腳本。預防:設計前置效能假設與驗證里程碑。
  • 難度: 初級
  • 學習階段: 基礎
  • 關聯概念: A-Q11, A-Q13, A-Q15, C-Q9

Q9: ORM 對應錯誤混淆了 EF/NH 名稱,怎麼避免?

  • A簡: 建立命名對照表、寫下約定、在程式與文件一律使用同一術語。
  • A詳: 症狀:團隊溝通與設定出現 TPH/TPT/TPC 與 NH 名稱交叉誤用。原因:工具間命名差異。解法:1) 引用對照(A-Q20);2) 將約定加入開發模板與 code review 清單;3) 單元測試覆蓋映射設定。預防:入門訓練與術語表,將對照貼在設計文件首部。
  • 難度: 初級
  • 學習階段: 基礎
  • 關聯概念: A-Q20, B-Q10, C-Q10

Q10: 如何建立選型自動化檢核以預防策略選擇錯誤?

  • A簡: 將查詢模式、資料量、約束需求轉為檢核清單,CI 內建原型基準測試。
  • A詳: 症狀:晚期才發現策略不適配。原因:缺乏量化檢核與早期基準。解法:1) 建選型問卷(查詢比例、資料量、約束等);2) 自動生成三策略原型與資料集;3) CI 跑 CRUD 與關鍵查詢基準;4) 以門檻自動報告建議。預防:把選型檢核納入變更管理流程。
  • 難度: 中級
  • 學習階段: 進階
  • 關聯概念: C-Q9, B-Q9, B-Q10

學習路徑索引

  • 初學者:建議先學習哪 15 題
    • A-Q1: 什麼是物件導向中的繼承?
    • A-Q2: 為什麼繼承是 OOP 的核心?
    • A-Q3: 什麼是 ORM?與繼承有何關係?
    • A-Q4: RDBMS 與 OOP 的差異是什麼?為何需要映射?
    • A-Q7: 什麼是 Table per Hierarchy (TPH)?
    • A-Q8: 什麼是 Table per Type (TPT)?
    • A-Q9: 什麼是 Table per Concrete Type (TPC)?
    • A-Q10: TPH、TPT、TPC 的差異為何?
    • A-Q11: 何時適合使用 TPH?
    • A-Q13: 何時適合使用 TPT?
    • A-Q15: 何時適合使用 TPC?
    • A-Q17: 什麼是正規化與反正規化?對繼承映射的意義?
    • B-Q5: 各策略的插入流程差異?
    • B-Q6: 各策略的更新與刪除流程差異?
    • C-Q1: 如何設計一個 TPH 的資料表架構?
  • 中級者:建議學習哪 20 題
    • A-Q5: 什麼是 virtual table?在 OOP 中扮演什麼角色?
    • A-Q6: virtual table 與資料庫 table schema 的類比是什麼?
    • A-Q12: 何時不適合使用 TPH?
    • A-Q14: 何時不適合使用 TPT?
    • A-Q16: 何時不適合使用 TPC?
    • A-Q18: 為何 TPH 被稱為最簡單的實作方式?
    • A-Q19: 為何在 TPT 中每個類別變動都容易?
    • A-Q20: EF 與 NH 對三種策略的命名對應?
    • B-Q1: TPH 如何運作?
    • B-Q2: TPT 的執行流程為何?
    • B-Q3: TPC 的機制是什麼?
    • B-Q4: 以單一查詢取得所有子類別物件在各策略如何達成?
    • B-Q7: TPT 的鍵與關聯應如何設計?
    • B-Q8: 欄位調整在三種策略中的影響與流程?
    • B-Q9: 以正規化觀點解讀三種策略的技術取捨?
    • B-Q10: EF/NH 如何在概念層支持三種策略?
    • C-Q3: 如何設計一個 TPT 的資料表與鍵?
    • C-Q4: 如何在 TPT 中撰寫查詢以載入子類別資料?
    • C-Q6: 如何用 SQL UNION 支援 TPC 的基底型別查詢?
    • C-Q10: 如何將 EF/NH 設定與資料表設計對齊?
  • 高級者:建議關注哪 15 題
    • C-Q7: 如何為 TPT 加入嚴格的表約束?
    • C-Q8: 如何在父類別新增欄位時同步 TPC 的所有表?
    • C-Q9: 如何選擇三種策略的實作清單與決策步驟?
    • D-Q1: TPH 表過大導致查詢效能差,怎麼辦?
    • D-Q2: TPH 無法對子類別做 NOT NULL 約束,如何處理?
    • D-Q3: TPT 層級深導致多層 JOIN 變慢,如何優化?
    • D-Q4: TPC 難以用單一查詢查出所有子類別,怎麼解?
    • D-Q5: 父類別欄位調整牽動 TPC 多表,如何降低風險?
    • D-Q6: 需要跨所有子類別做報表,該選哪種策略或怎麼設計?
    • D-Q7: 資料不一致出現在 TPC 的重複欄位,如何診斷與修復?
    • D-Q8: 專案初期不確定繼承階層深度,該如何規劃映射?
    • D-Q9: ORM 對應錯誤混淆了 EF/NH 名稱,怎麼避免?
    • D-Q10: 如何建立選型自動化檢核以預防策略選擇錯誤?
    • B-Q8: 欄位調整在三種策略中的影響與流程?
    • B-Q4: 以單一查詢取得所有子類別物件在各策略如何達成?





Facebook Pages

AI Synthesis Contents

Edit Post (Pull Request)

Post Directory