您的位置:首页 > 其它

Hibernate映射关系之一对一 and 一对多 or 多对一

2011-12-20 16:20 579 查看
个人原创,如有转载请指明出处,谢谢

将有很长一段时间不再使用Hibernate,现在将Hibernate常用的映射关系写在blog上,防止日后再次使用时又忘记了,哎,现在的脑子啊...

以学生和老师为例,首先说明单向的多对一和一对一的关系:

在同一课堂内,有N个学生,只有1个老师,所以学生对老师是单向的多对一,也可以做成双向的,但是这样就会有数据的冗余,再本章节最后才会说明双向关联

首先是老师的pojo类:

public class Teacher{

private Integer id; //ID,标识符

private String teacherName; //教师的名字

...省略getter、setter和构造方法

}

学生的pojo类:

public class Student{

private Integer id; //ID,唯一标识符

private String studentName; //学生的名字

Teacher teacher; //教师类对象

...省略getter、setter和构造方法

}

创建教师类的映射文件 Teacher.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="Teacher" table="teacher" >

<id name="id" type="int">

<column name="id" />

<generator class="identity"/>

</id>

<property name="teacherName" type="string"/>

</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="Student" table="student" lazy="false">

<id name="id" type="integer">

<column name="id" />

<generator class="identity" />

</id>

<property name="studentName" type="string" />

<many-to-one name="teacher" column="techer_id" class="Teacher" lazy="true" unique="true"/>

</class>

</hibernate-mapping>

在上述的xml中<many-to-one>标签说明存在一个多对一的映射关系,多对一的属性为Student类中的teacher属性(name的值),对应表中的列名为"teach_id"(column的值),映射关系另一方的类为Teacher类,这里需要写类全名,包括包名(class的值),lazy为延迟加载,俗称懒的初始化,为true时,在select 学生对象时,不会加载Teacher类对象,当需要一对一的关联关系时,红字部分为必须的,保证关系方的唯一性。在多对一的时候unique则为false

实际上,这里隐藏的告诉了Hibernate,teacher_id是外键,要引用Teacher类对应表的主键。

说这些是为了下面我们会使用Hibernate的一个类来为我们生成表。而不需要手动建表了:

public class CreateTable {

public static void main(String[] args) {

Configuration config = new Configuration().configure();

System.out.println("通过映射文件生成数据库的表");

SchemaExport se = new SchemaExport(config);

se.create(true, true);

System.out.println("完成生成数据库表");

}

}

在让Hibernate为我们建表之前,需要把Teacher.hbm.xml和Student.hbm.xml写好,并且添加进Hibernate.cfg.xml中的Mapping标签中。

反过来关联,一个老师对应多个学生的单向关联,一对多的关联关系如下:

首先是老师的pojo类:

public class Teacher{

private Integer id; //ID,标识符

private String teacherName; //教师的名字

private Set students = new HashSet(); //学生的集合

...省略getter、setter和构造方法

}

学生的pojo类:

public class Student{

private Integer id; //ID,唯一标识符

private String studentName; //学生的名字

...省略getter、setter和构造方法

}

学生类的映射关系描述文件:没什么特别

<?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="Student" table="student" lazy="false">

<id name="id" type="integer">

<column name="id" />

<generator class="identity" />

</id>

<property name="studentName" type="string" />

</class>

</hibernate-mapping>

教师类的映射关系描述文件:Teacher.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="Teacher" table="teacher">

<id name="id" type="int">

<column name="id" />

<generator class="identity" />

</id>

<property name="teacherName" type="string" />

<set name="students" inverse="false" fetch="select" cascade="save-update"

lazy="false">

<key column="teacher_id" />

<one-to-many class="Student" />

</set>

</class>

</hibernate-mapping>

关于<set>标签中的各个元素:

name:需要描述映射关系的类属性名

inverse:反转,默认为false,当为false的时候每次更新一次被关联方,就会再次更新一次关联方数据

fetch:指定了关联对象抓取的方式是select查询还是join查询,select方式时先查询返回要查询的主体对象(列表),再根据关联外键id,每一个对象发一个select查询,获取关联的对象,形成n+1次查询;而join方式,主体对象和关联对象用一句外键关联的sql同时查询出来,不会形成多次查询。如果关联的对象lazy=true,它不会去查询关联对象。

(通常情况下,我们并不使用映射文档进行抓取策略的定制。更多的是,保持其默认值,然后在特定的事务中,使用HQL的左连接抓取(left join fetch) 对其进行重载。这将通知 Hibernate在第一次查询中使用外部关联(outer join),直接得到其关联数据。 在条件查询 API中,应该调用 setFetchMode(FetchMode.JOIN)语句。 )

<key column="teacher_id" />:Student类对应表的关联外键为teacher_id

<one-to-many>:关联对方的class类型为:这里要类全名,包括包名。

一对多(多对一)的双向关联:

就是把上述两种关联方式结合起来。

老师的POJO类:

public class Teacher{

private Integer id; //ID,标识符

private String teacherName; //教师的名字

private Set students = new HashSet(); //学生的集合

...省略getter、setter和构造方法

}
学生的POJO类:

public class Student{

private Integer id; //ID,唯一标识符

private String studentName; //学生的名字

Teacher teacher; //教师类对象

...省略getter、setter和构造方法

}

教师类的映射关系描述文件:Teacher.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="Teacher" table="teacher">

<id name="id" type="int">

<column name="id" />

<generator class="identity" />

</id>

<property name="teacherName" type="string" />

<set name="students" inverse="true" fetch="select" cascade="delete"

lazy="false">

<key column="teacher_id" />

<one-to-many class="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="Student" table="student" lazy="false">

<id name="id" type="integer">

<column name="id" />

<generator class="identity" />

</id>

<property name="studentName" type="string" />

<many-to-one name="teacher" column="techer_id" class="Teacher" lazy="true"/>

</class>

</hibernate-mapping>

注意的是,不能在双方同时指定级联操作cascade="save-update",这样会产生一个org.hibernate.ObjectDeletedException。

因为删除操作也是属于update操作,在删除时,会激发关联的save方法,这是不允许的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: