在Hibernate的映射中多对一和一对多是核心。我们抽象出的大部分实体模型也都是多对一和一对多,而多对多的情况也是通过转换为一对多,多对一来实现的。那么这篇博客主要来讲解多对一关联的映射,下篇介绍一对多关联映射。
关联映射:就是将关联关系映射到数据库中,所谓的关联关系在对象模型中就是一个或多个引用。
多对一:我们以现实生活的实例对应理解,比如:用户和组:一个用户属于一个组,一个组中可以有多个用户,他们的关系是多对一的关系。可以简单的理解为用户知道组的存在,而组不知道用户的存在。那么hibernate需要再用户类中添加组的引用。具体我们看代码。
我们先来看一张UML图:
User端:
package com.bjpowernode.hibernate;
public class User {
private int id;
private String name;
private Group group; //持有组的引用
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
}
<?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>
Group 端:
package com.bjpowernode.hibernate;
public class Group {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<?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>
映射出的表结构如下:
为了验证是否正确,我们使用JUnit做个测试:
首先,编写一个HibernateUtils类:
package com.bjpowernode.hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private static SessionFactory factory;
static {
try {
//读取hibernate.cfg.xml文件
Configuration cfg = new Configuration().configure();
//建立SessionFactory
factory = cfg.buildSessionFactory();
}catch(Exception e) {
e.printStackTrace();
}
}
public static Session getSession() {
return factory.openSession();
}
public static void closeSession(Session session) {
if (session != null) {
if (session.isOpen()) {
session.close();
}
}
}
public static SessionFactory getSessionFactory() {
return factory;
}
}
编写我们的测试类:Many2oneTest
package com.bjpowernode.hibernate;
import java.util.Date;
import junit.framework.TestCase;
import org.hibernate.Session;
public class Many2OneTest extends TestCase {
public void testSave3() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Group group = new Group();
group.setName("TGB");
User user1 = new User();
user1.setName("张三");
user1.setGroup(group);
User user2 = new User();
user2.setName("李四");
user2.setGroup(group);
session.save(user1);
session.save(user2);
//没有抛出TransientObjectException异常
//因为使用了级联特性
//hibernate会首先保存User的关联对象对象Group
//Group和User就都是Persistent状态的对象了
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
public void testLoad1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
User user = (User)session.load(User.class, 3);
System.out.println("user.name=" + user.getName());
System.out.println("user.group.name=" + user.getGroup().getName());
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
}
总结:多对一关联映射的原理:在多的一端加入一个外键,指向一的一端。
我们特别关注的还有一点就是级联,级联是对象之间的连锁操作,它只影响增、删、改操作。
在上例中我们在User端:<many-to-one name="group" column="groupid" cascade="save-update"/>中添加了级联为save-update.就是在持久化User时级联持久化Group。