前言
在关联映射中,我们对每一种映射,按照对象模型,映射原理,配置,对象存储和加载的顺序来进行介绍。
这里强调一点,在关系模型中,实体之间的关系是不分方向的,在对象模型中,是分方向的,单向决定了从一端能看到另一端,反之则不行。双向则是两端可以互相看到。
多对一
关系模型
映射原理
刚才我们提到在关系模型中,对象之间的关系是部分方向的,所以当它们转化成数据库中的表时,不管是多对一,还是我们接下来要介绍的一对多,都是在“多”的一端加上“一”的主键作为外键。
配置
★User.java
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;
}
}
★User.hbm.xml
<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.java
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;
}
}
★Group.hbm.xml
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.Group" table="t_group">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
</class>
</hibernate-mapping>
【小结】:多对一关联映射中,只在“多”的一端的实体中对关联对象进行了引用,并在配置文件中进行了配置,“一”的一端的实体对象未做任何的修改和配置。
对象存储和加载
在学习这块内容中,我们要特别关注以下问题:
1. 对象本身和它关联的对象哪个先实例化,先存储
2. 加载某个对象时,能否也能加载它的关联对象
存储
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);
}
}
【小结】:存储的时候,一般先存储关联的对象,再存储自身,目的是让关联的对象也变成Persistent状态。当然我们也可以在配置文件中加入cascade=”save-update”,这样就不用显示的调用session.save(group)来对关联对象进行存储了。
加载
public void testLoad1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
User user = (User)session.load(User.class, 2);//发sql语句
System.out.println("user.name=" + user.getName());
System.out.println("user.group.name=" + user.getGroup().getName());//发sql语句
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
【小结】:
1. 我们看到在加载用户对应的组时,通过user.getGroup().getName()就可以加载,但是假如先通过load获得group,这里是不能通过group.getUser()来获得这个组中的用户的,因为在group中并没有进行配置。
2.Hibernate默认支持延迟加载,即<class name="com.bjpowernode.hibernate.User" table="t_user" lazy="true">
,此时默认的抓取策略为<many-to-one name="group" column="groupid" cascade="save-update" fetch="select"/>
,抓取策略指如何获取关联对象的策略,当使用fetch=”select”时,会先发出第一条sql语句查询当前对象,当使用到关联对象的属性时(查询user对应的组的名称),才会发出第二条sql语句。
总结
以上是最简单的关联映射,如果能从最简单的关联映射中总结出一些基本规律,那么学习之后的关联映射就会容易许多。在配置关系时,我们自己首先要清楚:要从哪个对象看到哪个对象以及谁来维护它们的关系。