Hibernate 支持將 Java Map 映射為關係表,Map 鍵值對應映射表的索引列與外鍵。本文詳細講解 無序 Map(HashMap) 與 有序 SortedMap(TreeMap) 兩種映射模式,含 XML 配置、實體類、自定義比較器、CRUD 測試全流程。
// Employee 一方
public class Employee {
private Integer id;
private String firstName, lastName;
private Integer salary;
private Map<String, Certificate> certificates; // 鍵:證書類型,值:證書對象
// Getter/Setter
}
// Certificate 多方
public class Certificate {
private Integer id;
private String name; // 證書名稱
// Getter/Setter
}
CREATE TABLE EMPLOYEE (
id INT PRIMARY KEY AUTO_INCREMENT,
first_name VARCHAR(20), last_name VARCHAR(20), salary INT
);
CREATE TABLE CERTIFICATE (
id INT PRIMARY KEY AUTO_INCREMENT,
certificate_type VARCHAR(40), -- Map 鍵
certificate_name VARCHAR(30), -- Certificate.name
employee_id INT, -- 外鍵
FOREIGN KEY (employee_id) REFERENCES EMPLOYEE(id)
);
<class name="Employee" table="EMPLOYEE">
<id name="id" column="id">
<generator class="native"/>
</id>
<map name="certificates" cascade="all">
<key column="employee_id"/>
<index column="certificate_type" type="string"/>
<one-to-many class="Certificate"/>
</map>
<property name="firstName" column="first_name"/>
<property name="lastName" column="last_name"/>
<property name="salary" column="salary"/>
</class>
<class name="Certificate" table="CERTIFICATE">
<id name="id" column="id"><generator class="native"/></id>
<property name="name" column="certificate_name"/>
</class>
關鍵點:
<map> 替代 <set>/<list>。<index> 定義 Map 鍵對應的列(certificate_type)。<key> 定義外鍵列(employee_id)。<one-to-many> 聲明值類型。在 <map> 元素添加 sort 屬性:
<map name="certificates" cascade="all" sort="com.example.MyComparator">
<key column="employee_id"/>
<index column="certificate_type" type="string"/>
<one-to-many class="Certificate"/>
</map>
sort 取值:
natural:鍵實現 Comparable,按自然序(String 字典序)。Comparator<K> 的自定義比較器類。public class MyComparator implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
// 反轉自然序
return o2.compareTo(o1);
}
}
// Map 版本
private Map<String, Certificate> certificates = new HashMap<>();
// SortedMap 版本
private SortedMap<String, Certificate> certificates = new TreeMap<>(new MyComparator());
// 保存
Employee emp = new Employee("Manoj", "Kumar", 4000);
SortedMap<String, Certificate> certs = new TreeMap<>(new MyComparator());
certs.put("ComputerScience", new Certificate("MCA"));
certs.put("BusinessManagement", new Certificate("MBA"));
certs.put("ProjectManagement", new Certificate("PMP"));
emp.setCertificates(certs);
session.save(emp);
// 查詢並遍歷(自動按比較器排序)
SortedMap<String, Certificate> map = emp.getCertificates();
for (Map.Entry<String, Certificate> e : map.entrySet()) {
System.out.println(e.getKey() + " -> " + e.getValue().getName());
}
// 輸出順序:ProjectManagement -> ComputerScience -> BusinessManagement(降序)
| 特性 | Map (HashMap) | SortedMap (TreeMap) |
|---|---|---|
| 順序 | 無序(插入順序不保證) | 按鍵排序(自然序/自定義 Comparator) |
| XML 配置 | <map> | <map sort="..."> |
| 初始化 | new HashMap<>() | new TreeMap<>(comparator) |
| 性能 | O(1) 讀寫 | O(log n) 讀寫 |
| 適用場景 | 不關心順序、高頻增刪 | 需有序遍歷、報表輸出 |
sort="natural" 要求鍵實現 Comparable,String 滿足,自定義鍵類需自行實現。Comparator<K>(K 為鍵類型)。cascade="all" 會級聯保存/刪除證書,若證書獨立生命週期請調整為 save-update。certificate_type 建議加唯一約束(employee_id, certificate_type),防止鍵重複。