千山万水之Hibernate(五)——关联映射(一对一)

知道了多对一关联映射的映射原理,我们再来看一对一关联的情况,一对一分映射有两种实现方案:

一对一主键关联映射

对于其中关联的情况我们又各分为单向、双向两种,而对于一对一,Hibernate采用one-to-one标签进行标识。

原理分析

我们拿人(Person)与身份证件(IdCard)为一对一关联对象的示例,他们的实体关系图为:
技术分享
采取第一种方案,则Person对应数据库表与IdCard对应数据库表中的主键是一一对应的,不需要添加多余的字段来表示外键。Person关联映射文件中的配置为:

<?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.tgb.hibernate.Person" table="t_person">
        <id name="id">
            <!-- 主键策略foreign -->
            <generator class="foreign">
                <!-- property指关联对象 -->
                <param name="property">idCard</param>
            </generator>
        </id>
        <property name="name" />
        <one-to-one name="idCard" constrained="true" />
    </class>
</hibernate-mapping>

注:one-to-one标签中的 constrained=”true”表示当前主键同时也是一个外键,参照IdCard中的主键。

操作示例

1.调用session的Load方法,得出Person对象的级联班级对象IdCard

public void testLoad(){
    Session session = null;
    Transaction tx = null;
    try{
        session = HibernateUtils.getSession();
        tx = session.beginTransaction();


        Person person = (Person)session.load(Person.class, 1);
        System.out.println("person.name = " + person.getName());
        System.out.println("person.idCard.cardNo = " + person.getIdCard().getCardNo());

        session.save(person);

        tx.commit();
    }catch(Exception e){
        e.printStackTrace();
        if(tx != null){
            tx.rollback();
        }
    }finally{
        HibernateUtils.closeSession(session);
    }
}

与上篇文章介绍的类似,通过one-to-one标签的作用,我们查询Person对象的同时,级联查询除了IdCard对象

2.默认级联保存Idcard机制

public void testSave(){
    Session session = null;
    Transaction tx = null;
    try{
        session = HibernateUtils.getSession();
        tx = session.beginTransaction();

        IdCard idCard = new IdCard();
        idCard.setCardNo("11111111111");

        Person person = new Person();
        person.setName("张三");
        person.setIdCard(idCard);

        session.save(person);

        tx.commit();
    }catch(Exception e){
        e.printStackTrace();
        if(tx != null){
            tx.rollback();
        }
    }finally{
        HibernateUtils.closeSession(session);
    }
}

上篇文章中我们提到过,在引用有Transient对象的Persistent状态的对象进行保存时,会出现异常,但在一对一主键关联映射上不会出现此种情况。也就是说,一对一默认带有cascade属性。对于一对一主键关联映射,双向关联的配置即是在IdCard端加入one-to-one标签即可,此标签仅影响加载,不影响存储。
综合来看将来如果改为多对一则不可修改,灵活性较差、扩展性不好。

一对一外键关联映射

我们可将一对一的情况看作是多对一情况的一种极端体现,我们可以采用many-to-one标签配合unique属性来给其相对应的表上添加外键字段,这种方式可解决使用主键关联映射的弊端。相关映射文件如下:

<?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.tgb.hibernate.Person" table="t_person">
        <id name="id">
            <generator class="native" />
        </id>
        <property name="name" />
        <many-to-one name="idCard" unique="true"></many-to-one>
    </class>
</hibernate-mapping>

有关相应的操作,可参照前一篇文章的多对一下示例。

总结

我们可以看到一对一主键关联到一对一外键关联的转变可以看作是另一种角度下看待问题,通过这样的思想,一些原本要求苛刻的情况我们同样可以通过另一种方式来处理,达到相同的效果,并且实现将来变更的灵活应对。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。