Joined Subclass(每類一表/連接繼承) 是最符合關係範式、支援多態查詢與關聯的標準策略。父類一表,每個子類一表,子表主鍵同時是指向父表的外鍵。本文詳細講解映射配置、SQL 生成、持久化操作與效能特徵。
EMPLOYEES (父表) — ID(PK), NAME, COMPANY_ID(FK)HOURLY_EMPLOYEES (子表) — EMPLOYEE_ID(PK, FK→EMPLOYEES), RATESALARIED_EMPLOYEES (子表) — EMPLOYEE_ID(PK, FK→EMPLOYEES), SALARYEmployee.hbm.xml 統一映射<hibernate-mapping>
<class name="mypack.Employee" table="EMPLOYEES">
<id name="id" column="ID"><generator class="increment"/></id>
<property name="name" column="NAME"/>
<many-to-one name="company" column="COMPANY_ID" class="mypack.Company"/>
<!-- 子類映射內嵌在父類映射中 -->
<joined-subclass name="mypack.HourlyEmployee" table="HOURLY_EMPLOYEES">
<key column="EMPLOYEE_ID"/> <!-- PK+FK -->
<property name="rate" column="RATE" type="double"/>
</joined-subclass>
<joined-subclass name="mypack.SalariedEmployee" table="SALARIED_EMPLOYEES">
<key column="EMPLOYEE_ID"/>
<property name="salary" column="SALARY" type="double"/>
</joined-subclass>
</class>
</hibernate-mapping>
關鍵點:<key column="EMPLOYEE_ID"/> 聲明子表主鍵兼外鍵列。子類無需獨立映射文件,初始化時僅註冊父類 config.addClass(Employee.class) 即可。
// 查詢所有 HourlyEmployee (內連接)
SELECT * FROM HOURLY_EMPLOYEES he INNER JOIN EMPLOYEES e ON he.EMPLOYEE_ID=e.ID;
// 查詢所有 Employee (左外連接,多態)
SELECT * FROM EMPLOYEES e
LEFT JOIN HOURLY_EMPLOYEES he ON e.ID=he.EMPLOYEE_ID
LEFT JOIN SALARIED_EMPLOYEES se ON e.ID=se.EMPLOYEE_ID;
Hibernate 根據子表 EMPLOYEE_ID 是否為 NULL 判斷實例類型:非 NULL → 對應子類實例。
映射 <one-to-many class="Employee"/> 即可支援多態集合。配合 lazy="true" 需手動 Hibernate.initialize(company.getEmployees()) 或配置 fetch="join" 迫切加載。
Employee emp = new HourlyEmployee("Mary", 300, company);
session.save(emp);
生成 SQL:
INSERT INTO EMPLOYEES (ID, NAME, COMPANY_ID) VALUES (5, 'Mary', 1);
INSERT INTO HOURLY_EMPLOYEES (EMPLOYEE_ID, RATE) VALUES (5, 300);
共享同一主鍵值 (5),事務保證原子性。
若拆分 HourlyEmployee.hbm.xml,需顯式聲明 extends="mypack.Employee",且初始化順序必須父類先於子類:
config.addClass(Company.class).addClass(Employee.class).addClass(HourlyEmployee.class);
順序顛倒會拋 HibernateMappingException。
| 優點 | 缺點 |
|---|---|
| ✅ 完全符合 3NF 範式 ✅ 支援多態查詢/關聯 ✅ 非空約束可加在子表字段 ✅ 父表無稀疏列 |
❌ 多態查詢需多表 JOIN,效能遜於單表 ❌ 保存/更新涉及多表操作 ❌ 映射配置相對複雜 |
Joined Subclass 是「正規化建模」與「物件多態」的最佳平衡點,掌握其連接查詢機制對性能調優至關重要。