首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

一对多单向跟双向映射

2012-10-17 
一对多单向和双向映射一、一对多单向关联多对一与一对多类似一对多映射中,只需要在一方的POJO中加入Set.在

一对多单向和双向映射

一、一对多单向关联

多对一与一对多类似
一对多映射中,只需要在一方的POJO中加入Set.
在一方的映射中加入:
<set name="students">
?<key column="class_id"></key>
?<one-to-many name="code">Hibernate一对多单向关联映射这种映射的本质是利用了多对一的关联映射的原理多对一关联映射:是在多的一端添加一个外键维护多指向一的关联引用一对多关联映射:是在多的一端添加一个外键维护一指向多的关联引用也就是说,一对多和多对一的映射策略是一致的,只是站的角度不同缺点: * 更新student表中的classesid字段时,需要对每一个student发出一个update的sql, 来更新classesid字段 * 如果将t_student表中的classesis设置为非空,则不能保存student数据,因为关系是由 classes维护的,在保存student时,还没有对应的classesid被生成

?

?

具体示例如下:

package com.lwf.hibernate.pojo;import java.util.HashSet;import java.util.Set;public class Classes {private int id;private String name;private Set students = new HashSet();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;}}

?

package com.lwf.hibernate.pojo;public class Student {private int id;private String name;private int age;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 int getAge() {return age;}public void setAge(int age) {this.age = age;}}

?

Classes.hbm.xml

<?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 package="com.lwf.hibernate.pojo"><class name="Classes" table="t_classes"><id name="id"><generator ><key column="class_id" ></key><one-to-many /></set></class></hibernate-mapping>

?Student.hbm.xml

<?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 package="com.lwf.hibernate.pojo"><class name="Student" table="t_student"><id name="id"><generator name="code">mysql> desc student;+----------+--------------+------+-----+---------+----------------+| Field    | Type         | Null | Key | Default | Extra          |+----------+--------------+------+-----+---------+----------------+| id       | int(11)      | NO   | PRI | NULL    | auto_increment || name     | varchar(255) | YES  |     | NULL    |                || class_id | int(11)      | YES  | MUL | NULL    |                |+----------+--------------+------+-----+---------+----------------+3 rows in set (0.06 sec)mysql> desc t_class;+-------+--------------+------+-----+---------+----------------+| Field | Type         | Null | Key | Default | Extra          |+-------+--------------+------+-----+---------+----------------+| id    | int(11)      | NO   | PRI | NULL    | auto_increment || name  | varchar(255) | YES  |     | NULL    |                |+-------+--------------+------+-----+---------+----------------+

?

?测试方法:

package com.lwf.hibernate.test;import java.util.HashSet;import java.util.Iterator;import java.util.Set;import junit.framework.TestCase;import org.hibernate.Session;import com.lwf.hibernate.pojo.Classes;import com.lwf.hibernate.pojo.Student;import com.lwf.hibernate.util.HibernateUtil;public class One2Many_Test extends TestCase{//从classes这一端来维护,即在单方维护,会产生insert和update语句.public void testClasses(){Session session = HibernateUtil.getSession();session.beginTransaction();try{Set students = new HashSet();for(int i=0;i<5;i++){Student s = new Student();s.setName("name" + i);s.setAge((10 + i));students.add(s);session.save(s);}Classes cla = new Classes();cla.setName("class1");cla.setStudents(students);session.save(cla);//先保存,最后根据class_id更新StudentHibernateUtil.commit(session);}catch(Exception e){HibernateUtil.roolback(session);}finally{HibernateUtil.closeSession(session);}}public void testLoad(){Session session = HibernateUtil.getSession();session.beginTransaction();try{Classes s = (Classes)session.load(Classes.class, 1);Set student = s.getStudents();for (Iterator iterator = student.iterator(); iterator.hasNext();) {Student stu = (Student) iterator.next();System.out.println(stu.getName());}HibernateUtil.commit(session);}catch(Exception e){HibernateUtil.roolback(session);}finally{HibernateUtil.closeSession(session);}}}

?

?

注意保存生成的语句:

Hibernate: insert into t_student (name, age) values (?, ?)Hibernate: insert into t_student (name, age) values (?, ?)Hibernate: insert into t_student (name, age) values (?, ?)Hibernate: insert into t_student (name, age) values (?, ?)Hibernate: insert into t_student (name, age) values (?, ?)Hibernate: insert into t_classes (name) values (?)Hibernate: update t_student set class_id=? where id=?Hibernate: update t_student set class_id=? where id=?Hibernate: update t_student set class_id=? where id=?Hibernate: update t_student set class_id=? where id=?Hibernate: update t_student set class_id=? where id=?

?

先保存student,再保存classes最后根据classes的id更新student的class_id

这实际上是由classes这方来维护两者的关联关系.

正常情况下关系应该由多的一方来维护,在双向关联中我们从多方来维护两者的关系.这样就可以避免update语句的出现.而是直接insert即可.

?

二、一对多双向关联

?

下面我们看看双向的一对多映射,实际上就是把一对多与多对一结合起来看.

Hibernate 一对多双向关联映射一对多双向关联映射的方法:在一一端:在集合标签里面使用<key>标签来表明需要在对方的表中添加一个外键指向一一端。在多一端:使用<many-to-one>标签来映射。需要注意:<key>标签所指定的外键字段名需要与<many-to-one>标签定义的外键字段名一致,否则便会造成引用数据的丢失!--------------------------------------------------如果从一端来维护一对多双向关联的关系,hibernate会发出多余的update语句,所以一般地情况下,我们便会从多一端来维护其关联关系!----------------------------------------------------

??

?

?在单向映射的基础上加上多对一关联即可.更改的文件:

package com.lwf.hibernate.pojo;public class Student {private int id;private String name;private int age;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 int getAge() {return age;}public void setAge(int age) {this.age = age;}public Classes getClasses() {return classes;}public void setClasses(Classes classes) {this.classes = classes;}}

?

Student.hbm.xml

<?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 package="com.lwf.hibernate.pojo"><class name="Student" table="t_student"><id name="id"><generator column="class_id"></many-to-one></class></hibernate-mapping>

?

即从Student的角度就是多对一,而从Classes角度就是一对多.

此时的表结构与单向的时候是一样的.

package com.lwf.hibernate.test;import java.util.HashSet;import java.util.Iterator;import java.util.Set;import junit.framework.TestCase;import org.hibernate.Session;import com.lwf.hibernate.pojo.Classes;import com.lwf.hibernate.pojo.Student;import com.lwf.hibernate.util.HibernateUtil;public class One2Many_Test extends TestCase{//从classes这一端来维护,即在单方维护,会产生insert和update语句.public void testClasses(){Session session = HibernateUtil.getSession();session.beginTransaction();try{Set students = new HashSet();for(int i=0;i<5;i++){Student s = new Student();s.setName("name" + i);s.setAge((10 + i));students.add(s);session.save(s);}Classes cla = new Classes();cla.setName("class1");cla.setStudents(students);session.save(cla);//先保存,最后根据class_id更新StudentHibernateUtil.commit(session);}catch(Exception e){HibernateUtil.roolback(session);}finally{HibernateUtil.closeSession(session);}}//由于配置了双向关联,所以下面先保存了classes再保存student只有insert语句,没有update语句public void testStudent(){Session session = HibernateUtil.getSession();session.beginTransaction();try{Classes cla = new Classes();cla.setName("class111");session.save(cla);for (int i = 0; i < 5; i++) {Student s  = new Student();s.setName("name111"+i);s.setClasses(cla);session.save(s);}HibernateUtil.commit(session);}catch(Exception e){HibernateUtil.roolback(session);}finally{HibernateUtil.closeSession(session);}}//从classes得到student,主要测试单向关联public void testLoadClass(){Session session = HibernateUtil.getSession();session.beginTransaction();try{Classes s = (Classes)session.load(Classes.class, 1);Set student = s.getStudents();for (Iterator iterator = student.iterator(); iterator.hasNext();) {Student stu = (Student) iterator.next();System.out.println(stu.getName());}HibernateUtil.commit(session);}catch(Exception e){HibernateUtil.roolback(session);}finally{HibernateUtil.closeSession(session);}}//从student得到classes,配置了双向关联后的测试public void testLoadStudent(){Session session = HibernateUtil.getSession();session.beginTransaction();try{Student s = (Student)session.load(Student.class, 1);System.out.println(s.getName());System.out.println(s.getClasses().getName());HibernateUtil.commit(session);}catch(Exception e){HibernateUtil.roolback(session);}finally{HibernateUtil.closeSession(session);}}}

主要区别:

由于配置了双向关联,所以下面先保存了classes再保存student只有insert语句,没有update语句

以下是testStudent方法产生的SQL语句

Hibernate: insert into t_classes (name) values (?)Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)

?

?

?

三、下面讨论一下关于INVERSE的用法:

关于inverse属性:inverse属性可以被设置到集合标签<set>上,表示在存储双向一对多关联映射的时候,存储的是那一方的关联引用。默认情况下,inverse=“false”,所以,我们可以从一一端或者多一端来维护两者之间的关系;如果我们设置inverse=“true”,则只能通过多一端来维护两者之间的关系。inverse属性可以被用在一对多和多对多双向关联中;注意:inverse属性只是在将数据持久化到数据库的过程中发挥作用.

?

主要看看上面双向关联中testClasses方法,当classes.hbm.xml文件如下时

<?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 package="com.lwf.hibernate.pojo"><class name="Classes" table="t_classes"><id name="id"><generator ><key column="class_id" ></key><one-to-many /></set></class></hibernate-mapping>

?我们知道上面的testClasses方法产生的sql语句是先insert再update,上面已经讲到是从一方来维护关联关系的.那么现在我们把classes.hbm.xml的set上面增加inverse="true"即

<set name="students" inverse="true"><key column="class_id" ></key><one-to-many /></set>

?那么这时候testClasses方法产生的SQL语句是?

Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)Hibernate: insert into t_classes (name) values (?)

?

虽然只产生了insert语句,但因为t_classes插入语句在后,所以数据库里面对应的t_student的记录:

mysql> select * from t_student;+----+-------+------+----------+| id | name  | age  | class_id |+----+-------+------+----------+|  1 | name0 |   10 |     NULL ||  2 | name1 |   11 |     NULL ||  3 | name2 |   12 |     NULL ||  4 | name3 |   13 |     NULL ||  5 | name4 |   14 |     NULL |+----+-------+------+----------+

?显然class_id为空.没有更新.

即用了INVERSE,将强制要求从多的一方来维护关系.即当设置了INVERSE属性后,要求使用testStudent方法来做保存.

而INVERSE属性没有设置时,对于双向的一对多关联,我们即可以使用testClasses又可以使用testStudent方法进行保存,但是他们的区别是testClasses操作中有insert和update语句,而testStudent只有insert语句.显然使用testStudent即从多方来维护关联关系节约了资源...

热点排行