Hibernate框架——关系操作(二)

前一篇文章( Hibernate框架——关系操作(一))中编写了Hibernate的基本操作: 一对多单项关联,一对多双向关联。那么现Hibernate中的多对多的关联操作。

多对多的双向关联

Course 类

1
2
3
4
5
6
7
public class Course implements Serializable{
private Long cid;
private String name;
private String description;
private Set<Student> students;
//set和get 方法由于版面的问题,在此就不再写出。
}

Student类

1
2
3
4
5
6
7
public class Student implements Serializable{
private Long sid;
private String name;
private String description;
private Set<Course> course;
//set和get 方法由于版面的问题,在此就不再写出。
}

1. 一对多体现的是类与集合的关系
2. 多对一体现的是类与类之间的关系
3. 多对多体现的是类与集合之间的关系

Course.hbm.xml 配置文件中的set元素

1
2
3
4
5
6
7
8
9
10
11
12
<set name="students" table="student_course" cascade="save-update">
<!-- table为关联表, 为了生成关联的sql语句-->
<key>
<column name="cid"></column>
<!--course通过cid与student_course表关联-->
</key>
<!--class: 描述类与类之间的关系
column:student 表通过sid与studnet_course表关联
-->
<many-to-many class="com.wcc.hibernate.domain.Student" column="sid"/>
</set>

Student.hbm.xml 配置文件中的set元素

1
2
3
4
5
6
7
8
9
10
<set name="courses" table="student_course" cascade="save-update">
<!-- table为关联表, 为了生成关联的sql语句-->
<key>
<column name="sid"></column>
<!--student通过sid与student_course进行关联-->
</key>
<many-to-many class="com.wcc.hibernate.domain.Course" column="cid">
<!--Course表通过cid来与student_course表进行关联-->
</many-to-many>
</set>

关系维护

1. 建立关系,相当于在第三张表中插入一行数据。
2. 解除关系,相当于在第三张表中删除一行数据。
3. 重新建立关系,相当于先删除一行数据,再增加一行数据。
4. 多对多,谁维护关系效率都一样。

操作

让一个新的学生和一个已经存在的课程发生关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Test
public void testSaveStudent_BuildR(){
Session session = HibernateUtils.sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Course course = (Course) session.get(Course.class, 1L);
// 得到cid为1的课程
// 创建一个学生
Student student = new Student();
student.setName("黄晓明");
student.setDescription("很帅");
//为这个学生创建一个 课程的集合
//course.getStudents().add(student);
//通过课程关联学生,这样的操作效率是比较低的,
//因为要根据课程查询学生要发出SQL语句。
Set<Course> courses = new HashSet<Course>();
// 添加取出的课程 到课程的集合中
courses.add(course);
// 给这个学生对象设置课程的集合
//通过学生建立与课程之间的联系。
student.setCourse(courses);
// 保存这个student对象
session.save(student);
transaction.commit();
}

说明:course.getStudents().add(student);是通过课程建立课程与学生之间的关联,执行course.getStudents()的时候,因为要查询该门课程中的所有学生,会发出根据课程查找该学生的SQL语句,这样做的效率比较低。

解除一个学生和一门课程之间的关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 解除一个学生和一门课程之间的关系
*/
@Test
public void testReleaseR(){
Session session = HibernateUtils.sessionFactory.getCurrentSession();
Transaction transaction =session.beginTransaction();
Student student = (Student) session.get(Student.class, 1L);
Course course = (Course) session.get(Course.class, 1L);
//通过学生解除关系
student.getCourse().remove(course);
//通过课程解除关系
//course.getStudents().remove(student);
transaction.commit();
}

解除该课程和这门课程所有的学生之间的关系

1
2
3
4
5
6
7
8
9
10
11
/**
*解除该门课程和所有的学生之间的关联
*/
@Test
public void testRealseAllR(){
Session session = HibernateUtils.sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Course course = (Course) session.get(Course.class, 1L);
course.setStudents(null);
transaction.commit();
}

一个学生从一门课程转移到另外一门课程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 一个学生从一门课转移到另一门的课程中。
*/
@Test
public void testChangeCourse(){
Session session = HibernateUtils.sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Course course = (Course) session.get(Course.class, 1L);
Course course2 = (Course) session.get(Course.class, 2L);
Student student = (Student) session.get(Student.class, 1L);
// 先解这个对象,然后在进行
student.getCourse().remove(course);
// 添加新的关系课程到这个集合中
student.getCourse().add(course2);
// 提交
transaction.commit();
}

一对一的双向

1
2
3
4
<many-to-one name="classes" column="cid"
class="com.wcc.hibernate.domain.Classes"
cascade="save-update" unique="true" >
</many-to-one>

外键在student表中不能出现相同的值,外键是唯一的,所以是一对一的。

1
2
3
4
5
Classes classes = (Classes)session.get(Classes.class,6L);
student1.setClasses(classes);
student2.setClasses(classes);
session.save(student2);
session.save(student1);

以上的代码是不对的,因为上面的代码会导致student1和student2的外键都是为6L,不符合外键也是唯一的约束了。

总结

1. 关系角度
一对多反映的是类与集合的关系
多对一反映的是类与类 之间的关系
多对多反映的是类与集合之间的关系
2. 一对多,多的一方维护关系,效率比较高
3. 多对多,谁维护效率都一样
4. 通过谁建立关系,就看谁的映射文件
5. Cascade 与inverse之间的区别(详见上面专门对Cascade与inverse的区别)

坚持原创技术分享,您的支持将鼓励我继续创作!