【One to one】
一对一关联映射包括主键关联,唯一外键关联两种,其中又分单向映射和双向映射两种。【主键单向】
每个人都有对应自己身份的身份证,这是唯一的,这就是现实生活中最常见的一对一的例子。想通过Person得知对应的IDcard,对象图形中,关联是有方向的,只能通过Person找到IdCard。关联图形中,主键关联映射,就是让两个实体的主键一样。主键关联的意思就是让两个对象具有相同的主键值,表名它们之间的一对一对应的关系,数据库表不会有额外的字段来维护它们之间的关系,仅仅通过表的主键来关联。但是主键的扩展性不太好,实际应用少。
Person.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.Person" table="t_Person">
<id name="id">
<generator class="foreign">
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<one-to-one name="idCard" constrained="true"/>
</class>
</hibernate-mapping>
<one-to-one> 指示Hibernate如何加载其关联对象,默认根据主键加载,也就是拿到关系字段值,根据对端主键来加载关联对象。其中 constrained="true" 表示 当前主键(person主键)还是一个外键,参照了对端的主键(idCard主键),会生成外键约束语句。采用foreign映射策略才能取得关联对象的标识。One2OneTest代码:
package com.bjpowernode.hibernate;
import org.hibernate.Session;
import junit.framework.TestCase;
public class One2OneTest extends TestCase {
public void testSave1(){
Session session=null;
try{
session=HibernateUtils.getSession();
session.beginTransaction();
IdCard idCard = new IdCard();
idCard.setCardNo("111111111111111");
Person person=new Person();
person.setName("辛巴");
//建立关联
person.setIdCard(idCard);
//保存维护关系的那一端
session.save(person);
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();
Person person=(Person)session.load(Person.class, 1);
System.out.println("person.name="+person.getName());
System.out.println("person.cardNo="+person.getIdCard().getCardNo());
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
}
在运行testSave1时,没有抛出transientObjectException。这是由一对一关联映射的特性决定的,它必须先保存关联对象IdCard,这样它采用foreign映射策略才能取得关联对象的标识,也就是它默认了cascade属性。
因为person端维护了关系,所以运行testLoad1,查person的时候就能顺带也把idcard查出来。
【主键双向】
想通过Person找到对应的IDcard,也想通过IDcard找到对应的Person,使用主键双向。如下图:
IdCard.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.IdCard" table="t_idCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
<!-- 指示hibernate将关联对象person根据主键加载上来 -->
<one-to-one name="person"/>
</class>
</hibernate-mapping>
【唯一外键单向】
我们想通过Person得知对应的IDcard,也可以使用单向唯一外键关联映射,其实是多对一特例,这种方法相对主键关联扩展性要好一些,所以也比较常用。
具体实现需要在Person.hbm.xml动手脚。采用<many- to- one> 标签来映射,指定多一端unique 为 true ,限制多的一端多重性为一即可。
<?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.Person" table="t_Person">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<!-- 多对一特例 -->
<many-to-one name="idCard" unique="true"/>
</class>
</hibernate-mapping>
【 唯一外键双向】
想通过Person找到对应的idCard,也根据idCard找到对应的Person,还想扩展性好一些,那就使用唯一外键双向关联。Person.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.Person" table="t_Person">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<many-to-one name="idCard" unique="true"/>
</class>
</hibernate-mapping>
在Person一端依旧使用<many-to-one>即多对一的特例来实现一对一。
IdCard.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.IdCard" table="t_idCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
<one-to-one name="person" property-ref="idCard"/>
</class>
</hibernate-mapping>
在IdCard一端,则采用 <one- to- one> 标签映射,必须指定 <one- to- one> 标签中的property-ref属性为关系字段的名称。这样使用了唯一外键,实现了双向关联。
【小结】
关于一对一,本文一共介绍了4种关联情况,常用的是唯一外键单双向管理。希望能对看官有帮助,下篇继续看hibernate的关联大法~