【一对多和多对一】
一对多和多对一映射原理是一样的,都是在多的一端加入一个外键指向一的一端。区别就在于维护关系不同。多对一维护关系,多指向一,如果维护了多指向一的关系,加载多的时候把一也加载出来。
一对多维护关系,一指向多,如果维护了一指向多的关系,加载一的时候会把多加载出来。
【单向】
一个班级有多个学生,要想从班级得知学生,就是在一的这段维护关系,就要在一的这端用集合set,谁负责维护关系谁就来写外键。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 >
<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>
One2ManyTest代码:
public void testSave1(){//从一端保存
Session session=null;
try{
session=HibernateUtils.getSession();
session.beginTransaction();
Student student1=new Student();
student1.setName("辛巴");
session.save(student1);// persistent
Student student2=new Student();
student2.setName("彭彭");
session.save(student2);// persistent
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);
}
}
在一的这端维护关系存在缺陷:
因为多的一端student不知道classes的存在,所以在保存student的时候关系字段classesid是为null的。如果将该关系字段设置为非空,则将无法保存数据。
另外因为student不维护关系,而classes维护关系,classes就会发出多余的update语句,为保证classes和student有关系,这样加载classes的时候才可以把该classes对应的学生加载上来。
【双向】
一对多关联都应设为双向,采用一对多双向关联映射的目的,主要是为了解决一对多单向关联的缺陷,而并不是需求驱动。我们需要让student,也就是“多”的这一端维护关系,为了让“一”的这端失效,我们需要设置映射属性 inverse ,设为true就是让对端负责更新。如果从一的这端保存,维护关系的字段就为空,所以我们只能从多端保存。
一对多双向关联的映射方式:
*在一的一端集合上采用<key>标签,在多的一端加入一个外键
*在多的一端采用<many-to-one>标签
*key标签和many to one标签加入的字段保持一致,否则会产生数据混乱
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 >
<class name="com.bjpowernode.hibernate.Classes" table="t_classes">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students" inverse="true">
<key column="classesid"/>
<one-to-many class="com.bjpowernode.hibernate.Student"/>
</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 >
<class name="com.bjpowernode.hibernate.Student" table="t_student">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<many-to-one name="classes" column="classesid"/>
</class>
</hibernate-mapping>
One2ManyTest代码:
public void testSave2(){//从多端保存
Session session=null;
try{
session=HibernateUtils.getSession();
session.beginTransaction();
Classes classes=new Classes();
classes.setName("一班");
session.save(classes);
Student student1=new Student();
student1.setName("辛巴");
student1.setClasses(classes);
session.save(student1);// persistent
Student student2=new Student();
student2.setName("彭彭");
student2.setClasses(classes);
session.save(student2);// persistent
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
【Inverse和级联】
级联是连锁性操作,是操作上的连锁反应,对增加删除修改起作用,不影响查询。inverse影响的是存储方向,是控制方向上的翻转,只影响存储,不影响加载。inverse属性可以用在一对多、多对多双向关联上,inverse属性默认为false,为false表示本端可以维护关系。true表示本端不能维护,交给另一端维护关系,本端失效。
所以一对多关联映射,我们通常在多的一端维护关系,让一的一端失效,设置inverse为true。