Hibernate双向一对多(多对一)

在上一篇文章中讲解了单向多对一的关联映射,总体来讲还是很好理解的。本文将会在上一篇文章的基础上讲解双向一对多的关联映射(双向的一对多和多对一是一样的)。

上一篇文章中的一的一端的持久化类是Grade,多的一端的持久化类是Student。Student类中存在Grade的实例,即对应的数据表存在外键映射,关联Grade。但是在Grade并没有去维护这种关联关系,如何让它成为双向的呢?我们在Grade中添加一个属性,如下:

private Set students = new HashSet();

这样便引用了Student的一个集合。这里有两个注意事项,我们在后文讲解。


持久化类修改了,hbm映射文件当然也需要修改。向下面这样为Student的集合属性添加配置:







       

上面的配置需要解释一下。由于不需要在Grade中再次生成外键(因为Grade和Student的关系已经由Student的外键维持了),所以Grade只需要维护这段关系中的一对多就可以了,所以我们需要告诉它关联表的名字,以及外键名。当然最后一步需要指定这是一对多映射并且指定集合属性的泛型(对应持久化类的类型),后面会用到的。


配置工作告一段落,来测试各种方法。

首先是save方法,测试如下:

	@Test
	public void testSave(){
		Grade grade = new Grade("高一", "初中到高中的过渡阶段");
		Student student = new Student("小刁", "男");
		Student student2 = new Student("小碧", "女");
		grade.getStudents().add(student);
		grade.getStudents().add(student2);
		student.setGrade(grade);
		student2.setGrade(grade);
		// 方式一:先插入one的一端,在插入many的一端,产生三条insert语句,两条update语句
		session.save(grade);
		session.save(student);
		session.save(student2);
		// 方式二:先插入many的一端,在插入one的一端,产生三条insert语句和两条update语句,四条update语句
/*		session.save(student);
		session.save(student2);
		session.save(grade);*/
		/*
		 * 在 1-n 关系中,将 n 方设为主控方将有助于性能改善(如果要国家元首记住全国人民的名字,
		 * 不是太可能,但要让全国人民知道国家元首,就容易的多)
		 * 在1的配置文件中集合上添加inverse="true"即可
		 * 这样以上的两种方法都会减少两条update语句
		 */
	}

先说一个小问题,为了能够正常的在save方法中使用Grade的set集合类,最好的情况是在持久化类中声明的时候就完成初始化,这样可以避免不必要的错误。

接着观察打印的SQL语句。我们发现和单向多对一不同,无论先保存哪一个持久化类的对象,都会出现update,为什么呢?因为现在的关系由双方共同维护,所以无论哪一方先保存,另外一方都需要更新。有改变的方法么?有的,在刚才的配置中添加一个属性inverse ,将其值设置为true。这样Grade变为被动方,这个双向关系现在由Student维护。在开发中鼓励这样做,因为在 1-n 关系中,将 n 方设为主控方将有助于性能改善(如果要国家元首记住全国人民的名字,不是太可能,但要让全国人民知道国家元首,就容易的多)。


然后再测试get方法,测试代码略过。大家可以自己试一试。然后重点看一下,使用Grade查询到对应的学生的集合的类型,我们发现返回的类型是Hibernate自带的集合类型,所以咱们又回到了上面的两个问题,第一个就是在Grade的持久化类中声明集合对象必须使用接口类型,因为Hibernate自定义的集合对象是java原生集合类型的实现。第二个是我上面说的配置中配置了“泛型”,什么意思呢?其实这也是我自己的理解,因为返回的是一个集合对象,所以系统需要告诉它泛型是什么。


更新操作读者自己完成吧,没有需要讲得。


删除操作就有问题了,在不指定级联属性的情况下,什么东西你都删除不了,因为Grade和Student是相互依赖的。所以这里需要设置另外一个属性cascade,它的值倒是种类很多,讲三个常用的:delete,delete-orphan,save-update。

delete表示删除一的一端则可以将多的一端对应的也一并删除。(年级没了,学生也没了)

delete-orphan表示删除一的一端并不会真的删除一,而是删除对应的多的一端。(年级取消,年级还在,学生没了)

刚才的讲解save的代码中,Grade和Student的对象是分开来保存的。save-update则可以让系统在保存Grade对象时,一并将关联的Student的对象也保存进数据库。

但是但是,重点来了,在开发中最好不要使用cascade属性,想要删除什么直接就去数据库删除就是了。


喔,对了,还有一个属性也很常用order-by属性,如果设置了该属性, 当 Hibernate 通过 select 语句到数据库中检索集合对象时, 利用 order by 子句进行排序,order-by 属性中还可以加入 SQL 函数。

你可能感兴趣的:(Hibernate双向一对多(多对一))