Hibernate一对多关联映射

来源:互联网 发布:网络装备交易排行榜 编辑:程序博客网 时间:2024/05/19 13:08

  上篇总结到多对一的关联映射,这篇总结一对多关联映射。

  一对多关联映射和多对一关联映射映射原理是一致的,都是在多的一端加入一个外键,指向一的一端。我们以班级和学生的例子理解。

  先看一张UML图:



Classes端:

package com.bjpowernode.hibernate;import java.util.Set;public class Classes {private int id;private String name;private Set students;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Set getStudents() {return students;}public void setStudents(Set students) {this.students = students;}}
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.bjpowernode.hibernate.Classes" table="t_classes"><id name="id"><generator class="native"/></id><property name="name"/><set name="students"> <key column="classesid" /><one-to-many class="com.bjpowernode.hibernate.Student"/></set></class></hibernate-mapping>

Student端:

package com.bjpowernode.hibernate;public class Student {private int id;private String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}}
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.bjpowernode.hibernate.Student" table="t_student"><id name="id"><generator class="native"/></id><property name="name"/></class></hibernate-mapping>

使用Junit测试:HibernateUtils类见上篇:

package com.bjpowernode.hibernate;import java.util.HashSet;import java.util.Iterator;import java.util.Set;import org.hibernate.Session;import junit.framework.TestCase;public class One2ManyTest extends TestCase {public void testSave1() {Session session = null;try {session = HibernateUtils.getSession();session.beginTransaction();Student student1 = new Student();student1.setName("张三");Student student2 = new Student();student2.setName("李四");Classes classes = new Classes();classes.setName("动力节点");Set students = new HashSet();students.add(student1);students.add(student2);classes.setStudents(students);//抛出TransientObjectException//因为Student不是Persistent状态的对象,它是Transient状态的对象session.save(classes);session.getTransaction().commit();}catch(Exception e) {e.printStackTrace();session.getTransaction().rollback();}finally {HibernateUtils.closeSession(session);}}public void testSave2() {Session session = null;try {session = HibernateUtils.getSession();session.beginTransaction();Student student1 = new Student();student1.setName("张三");session.save(student1);Student student2 = new Student();student2.setName("李四");session.save(student2);Classes classes = new Classes();classes.setName("动力节点");Set students = new HashSet();students.add(student1);students.add(student2);classes.setStudents(students);//可以成功保存数据//但是会发出多余的update语句来维持关系session.save(classes);session.getTransaction().commit();}catch(Exception e) {e.printStackTrace();session.getTransaction().rollback();}finally {HibernateUtils.closeSession(session);}}public void testLoad1() {Session session = null;try {session = HibernateUtils.getSession();session.beginTransaction();Classes classes = (Classes)session.load(Classes.class, 1);System.out.println("classes.name=" + classes.getName());Set students = classes.getStudents();for (Iterator iter=students.iterator(); iter.hasNext();) {Student student = (Student)iter.next();System.out.println("student.name=" +student.getName());}session.getTransaction().commit();}catch(Exception e) {e.printStackTrace();session.getTransaction().rollback();}finally {HibernateUtils.closeSession(session);}}}

  从测试中我们可以看到,多对一和一对多的区别:

* 多对一维护的关系是:多指向一的关系,有了此关系,在加载多的时候可以将一加载上来
* 一对多维护的关系是:一指向多的关系,有了此关系,在加载一的时候可以将多加载上来


  但是一对多有缺陷:

* 因为多的一端Student不知道Classes的存在(也就是Student没有维护与Classes的关系)所以在保存Student的时候关系字段classesid是为null的,如果将该关系字段设置为非空,则将无法保存数据
* 另外因为Student不维护关系,而Classes维护关系,Classes就会发出多余的update语句,保证Classes和Student有关系,这样加载Classes的时候才可以把该Classes对应的学生加载上来


  为了解决这个问题。我们通常采用一对多双向关联映射。双向关联比一对多单向关联的代码和配置不同在于:

Classes端一样,Student端多了Classes的引用。

package com.bjpowernode.hibernate;public class Student {private int id;private String name;private Classes classes;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Classes getClasses() {return classes;}public void setClasses(Classes classes) {this.classes = classes;}}
Classes端的配置文件中多了inverse属性

<set name="students" inverse="true"> <key column="classesid"/><one-to-many class="com.bjpowernode.hibernate.Student"/></set>

Student端的配置文件中多了many-to-one标签

<many-to-one name="classes" column="classesid"/>

!!!注意:<key>标签和<many-to-one>标签加入的字段保持一直,否则会产生数据混乱


  知识补充:inverse和cascade

* inverse属性可以用在一对多和多对多双向关联上,inverse属性默认为false,为false表示本端可以维护关系,如果inverse为true,则本端不能维护关系,会交给另一端维护关系,本端失效。所以一对多关联映射我们通常在多的一端维护关系,让一的一端失效,所以设置为inverse为true
* inverse是控制方向上的反转,只影响存储, cascade是操作上的连锁反映

总结:一对多关联映射和多对一关联映射映射原理是一致的,都是在多的一端加入一个外键,指向一的一端。




0 0