當繼承體系中的父類為非實體介面,或需關聯至不同表的多個具體子類時,標準的 <many-to-one> 無法滿足需求。Hibernate 提供 <any> 映射元素 實現「異構多態關聯」:一個外鍵欄位組合(類型判別欄 + ID欄)可指向多張不同表的記錄。
假設:
ClassB 映射表 TABLE_B,主鍵 IDClassC 映射表 TABLE_C,主鍵 IDClassD 映射表 TABLE_D,需關聯 B 或 C資料庫設計:TABLE_D 包含兩欄:
A_TYPE (VARCHAR) — 判別類型:'B' 或 'C'A_ID (BIGINT) — 對應目標表的主鍵值約束:無法在資料庫層面建立標準外鍵(因指向多表),需靠應用層或觸發器保證引用完整性。且 TABLE_B.ID 與 TABLE_C.ID 必須同樣 SQL 類型。
<any> 映射配置<class name="ClassD" table="TABLE_D">
<id name="id" column="ID"><generator class="increment"/></id>
<any name="a" meta-type="string" id-type="long" cascade="save-update">
<meta-value value="B" class="ClassB"/>
<meta-value value="C" class="ClassC"/>
<column name="A_TYPE"/> <!-- 判別欄,必須先聲明 -->
<column name="A_ID"/> <-- ID欄 -->
</any>
</class>
屬性解析:
name="a":實體屬性名,類型為公共父類/介面 ClassAmeta-type="string":判別欄 A_TYPE 的 Java 類型id-type="long":ID欄 A_ID 的 Java 類型meta-value:判別值與實體類的映射column 順序固定:先判別欄,後 ID 欄ClassD 時,Hibernate 依 A_TYPE 值決定實例化 ClassB 或 ClassC,並以 A_ID 去對應表載入。cascade="save-update" 級聯保存關聯對象。| 策略 | 表結構 | 多態查詢/關聯 | 優點 | 缺點 |
|---|---|---|---|---|
| 每具體類一表 (Table per Concrete Class) |
各子類獨立表,含繼承字段 | ❌ 不支援 | 簡單,無連接查詢 | 無多態,重複列,難維護 |
| 單表策略 (Table per Class Hierarchy) |
單表含所有字段 + 判別欄 | ✅ 支援,效能最佳 | 查詢快,無 Join | 違反範式,非空約束受限,稀疏表 |
| 每類一表 (Table per Subclass / Joined) |
父表 + 子表(主鍵兼外鍵) | ✅ 支援,符合範式 | 數據完整性,規範設計 | 查詢需 Join,效能稍遜 |
<any> 映射super(...) 初始化父類字段,方便業務代碼創建對象(Hibernate 僅用無參建構子)。掌握 <any> 映射,即可優雅解決「一個引用指向多張表」的異構多態難題,是 Hibernate 進階映射的關鍵技能。