上篇博客中介绍了Hibernate的基本映射,下面跟小编接着来学习Hibernate的关联映射吧。
关联映射,就是将关联关系映射到数据库中。所谓的关联关系就是在对象模型中就是一个或多个引用。在对象模型中,关联是有方向的。所以关系映射有四种:多对一、一对一、一对多、多对多。
【多对一】
1、需求:
User-Group多个用户属于某个组。例如当前有个项目需要几个人进行敏捷开发,于是需要从员工中挑几个人形成新的小组进行开发,待到项目完成之后小组自行解散。这是,User表和Group表就是多对一的关系,并且是聚合关系,由User指向Group,也就是说从用户可以看到Group,而从组看不到用户。
2、映射原理:
在多的一端加入一个外键,指向一的一端.在多的一端采用如下标签映射:
<many-to-one name="外键实体" column="外键名称"/>
下面来看一个小例子吧。项目结构如下图:
①Group实体类(Group.java):
package com.bjpowernode.hibernate;
public class Group {
private int id;
private String name;
// get和set略
}
②Group映射文件(Group.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.Group" table="t_group">
<id name="id">
<generator class="native" />
</id>
<property name="name" />
</class>
</hibernate-mapping>
③User实体类(User.java):
package com.bjpowernode.hibernate;
public class User {
private int id;
private String name;
private Group group;
// get和set略
}
④User映射文件(User.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.User" table="t_user">
<id name="id">
<generator class="native" />
</id>
<property name="name" />
<many-to-one name="group" column="groupid" />
</class>
</hibernate-mapping>
⑤其他的代码略(前面博客中有介绍)
建表结果如下图:
下面来添加一条数据试试。
测试方法如下:
public void testSave1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Group group = new Group();
group.setName("一班");
User user1 = new User();
user1.setName("张三");
user1.setGroup(group);
User user2 = new User();
user2.setName("李四");
user2.setGroup(group);
session.save(user1);
session.save(user2);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
HibernateUtils.closeSession(session);
}
}
但是结果却出错了,在清理缓存时会发生错误TransientObjectException,因为Group为Transient状态,没有被session,在数据库中没有匹配的数据,而User为Persistent状态,在清理缓存时hibernate在缓存中无法找到Group对象,结论是Persistent状态的对象不能引用Transient状态的对象
解决方法有二:第一,在保存User之前先执行保存外键实体Group;第二,在配置文件中添加级联属性配置,级联是对象之间的连锁操作,它只影响添加、删除和修改。具体实现如下:
第一种:
public void testSave2() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Group group = new Group();
group.setName("一班");
session.save(group);
User user1 = new User();
user1.setName("张三");
user1.setGroup(group);
User user2 = new User();
user2.setName("李四");
user2.setGroup(group);
session.save(user1);
session.save(user2);
// 可以正确的保存数据
// 因为Group和User都是Persistent状态的对象
// 所以在hibernate清理缓存时在session中可以找到关联对象
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
HibernateUtils.closeSession(session);
}
}
第二种:
<?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.User" table="t_user">
<id name="id">
<generator class="native" />
</id>
<property name="name" />
<many-to-one name="group" column="groupid" cascade="save-update" />
</class>
</hibernate-mapping>
【补充:级联】
级联属性cascade:是指定两个对象之间的操作联动关系,对一个对象执行了操作之后,对其指定的级联对象也需要执行相同的操作。有以下四种取值:
①all:代表在所有的情况下都执行级联操作。
②none:在所有情况下都不执行级联操作。
③save-update:在保存和更新的时候执行级联操作。
④delete:在删除的时候执行级联操作。