单向多对一关联映射
我们先来假设一个场景,从学生的角度看,学生和班级的关系就是多对一的关系,也就是多个学生属于一个班
级。多对一关联映射原理就是在多的一端加入一个外键,指向一的一端;在多的一端采用<many-to-one>标签映
射,也就是在Students.hbm.xml对象关系映射配置文件中采用,单向多对一关联映射是在多的一端来维护关联字
段,在我们这个例子中也就是在学生一端来维护关系字段。
如下图所示(图中关系表示多个用户属于一个组):
Student实体类:
package com.demo.entity;
import java.io.Serializable;
@SuppressWarnings("serial")
public class Student implements Serializable {
private int sid;
private String sname;
private String sex;
//在多方定义一个一方的引用
private Grade grade;
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Grade getGrade() {
return grade;
}
public void setGrade(Grade grade) {
this.grade = grade;
}
public Student() {
super();
}
public Student(String sname, String sex) {
super();
this.sname = sname;
this.sex = sex;
}
}
Student对象关系映射配置文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.demo.entity.Student" table="t1_student">
<id name="sid" column="sid" type="java.lang.Integer">
<generator class="increment"></generator>
</id>
<property name="sname" type="java.lang.String">
<column name="sname" length="20" not-null="true"></column>
</property>
<property name="sex">
<column name="sex"></column>
</property>
<!-- 配置单向多对一关联关系 -->
<many-to-one name="grade" class="com.demo.entity.Grade" column="gid"></many-to-one>
</class>
</hibernate-mapping>
Grade实体类:
package com.demo.entity;
import java.io.Serializable;
@SuppressWarnings("serial")
public class Grade implements Serializable {
private int gid;
private String gname;
private String gdesc;
public int getGid() {
return gid;
}
public void setGid(int gid) {
this.gid = gid;
}
public String getGname() {
return gname;
}
public void setGname(String gname) {
this.gname = gname;
}
public String getGdesc() {
return gdesc;
}
public void setGdesc(String gdesc) {
this.gdesc = gdesc;
}
public Grade() {
super();
}
public Grade(int gid, String gname, String gdesc) {
super();
this.gid = gid;
this.gname = gname;
this.gdesc = gdesc;
}
public Grade(String gname, String gdesc) {
super();
this.gname = gname;
this.gdesc = gdesc;
}
}
Grade对象关系映射配置文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.demo.entity.Grade" table="t1_grade">
<id name="gid" column="gid" type="java.lang.Integer">
<generator class="increment"></generator>
</id>
<property name="gname" type="java.lang.String">
<column name="gname" length="20" not-null="true"></column>
</property>
<property name="gdesc">
<column name="gdesc"></column>
</property>
</class>
</hibernate-mapping>
测试类代码:
package com.demo.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.demo.entity.Grade;
import com.demo.entity.Student;
import com.demo.util.HibernateUtil;
/**
* 单向多对一(学生--->班级)
* @author Administrator
* @date 2016年12月8日
*/
public class TestMany2One {
//将学生添加到班级
@Test
public void testSave1(){
Session session = HibernateUtil.getSession();
Transaction transaction= session.beginTransaction();
Grade g=new Grade("Java一班","Java软件开发一班");
Student stu1=new Student("张三", "男");
Student stu2=new Student("李四", "男");
//设置关联关系(单向多对一)
stu1.setGrade(g);
stu2.setGrade(g);
session.save(stu1);
session.save(stu2);
//在清理缓存是发生错误TransientObjectException
//因为Group为Transient状态,没有被session,在数据库中没有匹配的数据
//而User为Persistent状态,在清理缓存时hibernate在缓存中无法找到Group对象
//结论:Persistent状态的对象不能引用Transient状态的对象
transaction.commit();
HibernateUtil.closeSession(session);
}
//将学生添加到班级
@Test
public void testSave2(){
Session session = HibernateUtil.getSession();
Transaction transaction= session.beginTransaction();
Grade g=new Grade("Java一班","Java软件开发一班");
session.save(g);
Student stu1=new Student("张三", "男");
Student stu2=new Student("李四", "男");
//设置关联关系(单向多对一)
stu1.setGrade(g);
stu2.setGrade(g);
session.save(stu1);
session.save(stu2);
//可以正确的保存数据
//因为Group和User都是Persistent状态的对象
//所以在hibernate清理缓存时在session中可以找到关联对象
transaction.commit();
HibernateUtil.closeSession(session);
}
//将学生添加到班级
@Test
public void testSave3(){
Session session = HibernateUtil.getSession();
Transaction transaction= session.beginTransaction();
Grade g=new Grade("Java一班","Java软件开发一班");
Student stu1=new Student("张三", "男");
Student stu2=new Student("李四", "男");
//设置关联关系(单向多对一)
stu1.setGrade(g);
stu2.setGrade(g);
session.save(stu1);
session.save(stu2);
//没有抛出TransientObjectException异常
//因为使用了级联特性
//hibernate会首先保存User的关联对象对象Group
//Group和User就都是Persistent状态的对象了
transaction.commit();
HibernateUtil.closeSession(session);
}
//通过学生查询到班级名称
@Test
public void testLoad(){
Session session = HibernateUtil.getSession();
Transaction transaction= session.beginTransaction();
Student stu = (Student)session.load(Student.class, 1);
System.out.println("stu.sname=" + stu.getSname());
System.out.println("stu.grade.gname=" + stu.getGrade().getGname());
transaction.commit();
HibernateUtil.closeSession(session);
}
}
testSave1()方法
Junit测试不成功:
testSave2()方法
控制台输出:
数据库显示:
在测试testSave3()方法之前需要在Student.hbm.xml中的<many-to-one>标签中加入cascade属性,我们删除
数据库中的两张表,重新生成表结构,并且重新插入原来想要插入的数据。
<!-- 配置单向多对一关联关系,设置cascade="all" -->
<many-to-one name="grade" class="com.demo.entity.Grade" column="gid" cascade="all"></many-to-one>
testSave3()方法
控制台输出:和testSave2()方法的控制台输出结果一致
数据库显示:和testSave2()方法的数据库显示结果一致
testLoad()方法
控制台输出:
单向多对一关联映射和关系数据库中的外键参照关系最匹配,即在多方的表中的一个外键参照另外一个表的主
键。通过在多方持有一方的引用实现,需要在多的一端使用<many-to-one>配置这是关键,还有就是注意级联属性
casacde。
单向多对一关联映射维护的关系是:多指向一的关系,有了此关系,加载多的时候可以将一加载上来。