Person (人) 與 IdCard (身份證) 為一對一關係。採用主鍵關聯:兩表共用相同主鍵值,Person 表主鍵同時是指向 IdCard 的外鍵。無額外外鍵欄位,資料庫層面僅靠主鍵關聯。
// IdCard.java
public class IdCard {
private int id;
private String cardNo;
// getter/setter 略
}
// Person.java
public class Person {
private int id;
private String name;
private IdCard idCard; // 單向引用
// getter/setter 略
}
<hibernate-mapping>
<class name="com.cn.hibernate.IdCard" table="t_idcard">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.cn.hibernate.Person" table="t_person">
<id name="id" column="id">
<!-- foreign: 使用關聯物件的識別碼作為主鍵 -->
<generator class="foreign">
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<!-- 一對一關聯,constrained=true 建立外鍵約束 -->
<one-to-one name="idCard" constrained="true"/>
</class>
</hibernate-mapping>
<generator class="foreign">:告訴 Hibernate Person 的 id 不是自行產生,而是取自關聯屬性 idCard 的識別碼。<param name="property">idCard</param>:指定來源屬性名稱。<one-to-one name="idCard" constrained="true"/>:宣告單向一對一,並在資料庫建立外鍵約束 (Person.id 參照 IdCard.id),保證資料完整性;同時啟用預設的主鍵關聯載入策略 (透過 Person 主鍵查 IdCard)。<one-to-one name="person" constrained="true"/> 並調整生成策略。Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
IdCard card = new IdCard();
card.setCardNo("A123456789");
session.save(card); // 先存 IdCard,產生 id
Person person = new Person();
person.setName("王小明");
person.setIdCard(card); // 關聯
session.save(person); // Person 使用 card 的 id 作為主鍵
tx.commit();
session.close();
| 優點 | 缺點 |
|---|---|
| 資料庫結構簡潔,無額外外鍵欄位 | 被引用端 (IdCard) 必須先持久化,順序固定 |
| 主鍵即外鍵,Join 查詢效率高 | 難以支援雙向導航 (需額外配置) |
| 符合「共享主鍵」領域模型語意 | 若 IdCard 可被多個 Person 共享則不適用 |
主鍵關聯適合「強生命週期綁定」的一對一關係 (如 Person-IdCard、Order-OrderDetail)。若關係較鬆散,考慮唯一外鍵關聯 (加 unique="true" 的 many-to-one)。