組合是關聯關係中耦合度最高的一種:主物件與子物件共享相同生命週期,主物件消失則子物件隨之消失。以「員工/用戶」與「聯絡資訊」為例,雙方都擁有聯絡資訊屬性(email、address、zipCode、contactTel)。若從物件導向角度建模,可將聯絡資訊抽象為獨立 Contact 類別,員工與用戶各自包含一個 Contact 物件,形成組合關係。
Hibernate 將組合物件的屬性「扁平化」映射到主表中,不建立獨立子表。t_employee 與 t_user 表皆包含 contact 相關欄位:
create table t_employee (
id integer not null auto_increment,
name varchar(255),
email varchar(255),
address varchar(255),
zipCode varchar(255),
contactTel varchar(255),
primary key (id)
);
-- t_user 結構相同
public class Contact {
private String email, address, zipCode, contactTel;
// getter/setter 略
}
public class Employee {
private int id;
private String name;
private Contact employeeContact; // 組合物件
// getter/setter 略
}
<hibernate-mapping>
<class name="com.src.hibernate.Employee" table="t_employee">
<id name="id"><generator class="native"/></id>
<property name="name"/>
<component name="employeeContact">
<property name="email"/>
<property name="address"/>
<property name="zipCode"/>
<property name="contactTel"/>
</component>
</class>
</hibernate-mapping>
<component name="userContact">
<property name="email"/>
<property name="address"/>
<property name="zipCode"/>
<property name="contactTel"/>
</component>
因組合映射產生扁平化表結構,寫入與讀取皆採用最基本的 save / load 即可,無需特殊處理。
Session session = HibernateUtils.getSession();
session.beginTransaction();
Contact contact = new Contact();
contact.setAddress("北京市");
contact.setContactTel("1243435");
contact.setEmail("123@gmail.com");
contact.setZipCode("100000");
User user = new User();
user.setName("zhangsan");
user.setUserContact(contact); // 只需儲存 user,contact 會級聯保存
session.save(user);
session.getTransaction().commit();
生成 SQL:insert into t_user (name, email, address, zipCode, contactTel) values (?, ?, ?, ?, ?)
User user = (User) session.load(User.class, 1);
System.out.println("用戶姓名:" + user.getName());
// 會自動填充 userContact 所有屬性
另一個經典案例:帳戶包含地址資訊。
public class Account implements Serializable {
private int id;
private double money;
private Address address; // 組合物件
// getter/setter
}
public class Address implements Serializable {
private String code, city, province;
// getter/setter
}
<component name="address">
<property name="code"><column name="code"/></property>
<property name="city"><column name="city"/></property>
<property name="province"><column name="province"/></property>
</component>
<class>。掌握組合映射,能讓領域模型更豐富、資料庫結構更乾淨,是 Hibernate 進階必修課。