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方法,这是不允许的。
将有很长一段时间不再使用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方法,这是不允许的。
相关文章推荐
- hibernate关系映射管理(一对多,多对一,一对一,多对多)
- Hibernate双向一对一,一对多,多对多关系映射
- Hibernate的映射关系与级联(一对一、一对多、多对多)
- Hibernate 关系映射 (一对一,一对多,多对多)
- hibernate关系映射管理(一对多,多对一,一对一,多对多)
- Hibernate入门BLOG[七、Hibernate对象关系一对一映射]
- 3、Hibernate一对一、一对多、多对多对应关系
- 我的hibernate之旅~一对一关系映射
- java框架篇---hibernate(一对一)映射关系
- Mybatis(2、关系映射一对一、一对多、多对多)
- Hibernate 集合映射 一对多多对一 inverse属性 + cascade级联属性 多对多 一对一 关系映射
- hibernate一对一,一对多,多对一,多对多关系映射与级联
- Hibernate实体关系映射——双边的一对一关系
- [原创]java WEB学习笔记84:Hibernate学习之路-- -映射 一对一关系 ,基外键的方式实现
- Java程序员从笨鸟到菜鸟之(五十八)细谈Hibernate(九)hibernate一对一关系映射
- Hibernate关系映射级别注解(一对多单向外键关联、一对多(多对一)双向外键关联)
- Hibernate关系映射(3)_一对一单向主键关联
- 3、Hibernate一对一、一对多、多对多对应关系
- 3、Hibernate一对一、一对多、多对多对应关系
- 【HIbernate框架学习】:Hibernate对象关系映射之一对一关联映射(二)