繼一對一映射後,本文將深入講解 Hibernate 中最常用的兩種集合映射:多對多與一對多。透過「學生-老師」經典場景,展示雙向關聯的實體設計、映射檔配置與關鍵屬性(如 inverse、cascade)的實戰意義。
一個學生可選修多門課程(對應多位老師),一位老師可教授多名學生。資料庫需建立中間關聯表 t_s(student_id, teacher_id)。
// Student.java
public class Student {
private int id;
private String sname;
private Set<Teacher> teacherSet = new HashSet<>(); // 使用 Set 避免重複
// getter/setter 略
public Set<Teacher> getTeacherSet() { return teacherSet; }
public void setTeacherSet(Set<Teacher> teacherSet) { this.teacherSet = teacherSet; }
}
// Teacher.java
public class Teacher {
private int id;
private String tname;
private Set<Student> studentSet = new HashSet<>;
public Set<Student> getStudentSet() { return studentSet; }
public void setStudentSet(Set<Student> studentSet) { this.studentSet = studentSet; }
}
<!-- Student.hbm.xml -->
<class name="com.entity.Student" table="student">
<id name="id"><generator class="native"/></id>
<property name="sname" column="sname"/>
<set name="teacherSet" table="t_s" lazy="false" inverse="true" cascade="all">
<key column="s_id"/>
<many-to-many class="com.entity.Teacher" column="t_id" outer-join="auto"/>
</set>
</class>
<!-- Teacher.hbm.xml -->
<class name="com.entity.Teacher" table="teacher">
<id name="id"><generator class="native"/></id>
<property name="tname" column="tname"/>
<set name="studentSet" table="t_s" lazy="false" cascade="all">
<key column="t_id"/>
<many-to-many class="com.entity.Student" column="s_id" outer-join="auto"/>
</set>
</class>
一位老師指導多名學生,但一名學生僅屬於一位老師。資料庫中 student 表含外鍵 t_id 指向 teacher。
// Student.java(多方)
public class Student {
private int id;
private String sname;
private Teacher teacher; // 多對一關聯
public Teacher getTeacher() { return teacher; }
public void setTeacher(Teacher teacher) { this.teacher = teacher; }
}
// Teacher.java(一方)
public class Teacher {
private int id;
private String tname;
private Set<Student> students = new HashSet<>(); // 一對多集合
public Set<Student> getStudents() { return students; }
public void setStudents(Set<Student> students) { this.students = students; }
}
<!-- Student.hbm.xml -->
<class name="com.entity.Student" table="student">
<id name="id"><generator class="native"/></id>
<property name="sname" column="sname"/>
<!-- 多對一:由 Student 端維護外鍵 -->
<many-to-one name="teacher" class="com.entity.Teacher"
column="t_id" cascade="all" outer-join="auto"/>
</class>
<!-- Teacher.hbm.xml -->
<class name="com.entity.Teacher" table="teacher">
<id name="id"><generator class="native"/></id>
<property name="tname" column="tname"/>
<!-- 一對多:inverse="true" 表示由 Student 端的 many-to-one 維護關係 -->
<set name="students" lazy="false" inverse="true" cascade="all">
<key column="t_id"/>
<one-to-many class="com.entity.Student"/>
</set>
</class>
student 表,故 <many-to-one> 不需 inverse,負責維護關聯。cascade="delete" 或 "all";否則僅解除關聯。Set,避免重複元素;需排序可用 SortedSet 或 List(搭配 <index>)。lazy="true"(預設),搭配 OpenSessionInViewFilter 或 DTO 組裝避免 LazyInitializationException。teacher.getStudents().add(student); student.setTeacher(teacher);),確保記憶體中物件圖一致。多對多依賴中間表,一對多依賴外鍵欄位。掌握 inverse、cascade、lazy 三大屬性的語義與組合,是驅動 Hibernate 高效、正確處理集合關聯的關鍵。