hibernate入门(7)关联关系讨论_一对一关系映射

hibernate入门(七)关联关系讨论_一对一关系映射

典型的实例:一个人有一个身份证,而一个身份证只属于某一个人。以此为模型实现一对一关系的映射。下面的实例先以主键进行关联:

主键关联 从表的主键同时又作为外键参考主表的主键。比如在下面的实例中,人作为主表,身份证作为从表。

>> 步骤一,建立Person 类及相关的实体配置文件。

package com.asm.hibernate.domain;

public class Person {

    private int id ;

    private String name ;

    private IdCard idCard ;

}   ... 省略相应的get/set 方法。

配置文件:person.hbm.xml 和前面的配置一样,只需要留意下 </ one-to-one > 元素,内容如下:

< hibernate-mapping package = "com.asm.hibernate.domain" >

    < class name = "Person" >

       < id name = "id" >

           < generator class = "native" />

       </ id >

       < property name = "name" ></ property >

       < one-to-one name = "idCard" ></ one-to-one >

    </ class >

</ hibernate-mapping >

>> 步骤二,建立IdCard 类及相关的实体配置文件。

package com.asm.hibernate.domain;

import java.util.Date;

public class IdCard {

    private int id ;

    private Date validity ;

    private Person person ; 

} ... 省略相应的get/set 方法。

从表配置文件:IdCard.hbm.xml ,内容如下:

< hibernate-mapping package = "com.asm.hibernate.domain" >

    < class name = "IdCard" >

       < id name = "id" >

           < generator class = "foreign" >

              < param name = "property" > person </ param >

           </ generator >

       </ id >

       < property name = "validity" ></ property >

       < one-to-one name = "person" constrained = "true" ></ one-to-one >

    </ class >

</ hibernate-mapping >

配置文件说明:由于上面提到的是采取主键关联,即是说这里的id 即是主键,同时也是(关联相关表的)外键,因此,以下对id 的生成采取了”foreign” 方式,其实这种方式也就指明了主键同时为外键。下面的<param> 指定了外键的参考信息,此元素中的内容指明了它参考<one-to-one>person 。 注意在< one-to-one name = "person" constrained = "true" > 中设定了constrained 属性,其作用是说明该配置文件所映射表的主键同时作为外键,参照关联类对应表的主键。设定了此属性可用“show create table idcard ”查看表idcard 的定义发生了变化。

>> 步骤三,修改主配置文件,关联上面的实体配置文件。

>> 步骤四,编写测试类, OneToOneTest.java 内容如下:省略导入的包。

package com.asm.hibernate.test;

public class OneToOneTest {

    public static void main(String[] args) {

       add ();

    }

    static void add() {

        Session s = null ;

       Transaction tr = null ;

       try {

           s = HibernateUtil.getSession ();

           tr = s.beginTransaction();

 

           Person person = new Person();

           person .setName( "pName" );

           IdCard idCard = new IdCard();

           idCard.setValidity( new Date());

          

           // 分别注释掉以下两句,看程序执行情况

           person .setIdCard(idCard);

           idCard.setPerson(person );

 

           s.save(person );

           s.save(idCard);

           tr.commit();

       } finally {

           if (s != null )

              s.close();

       }

    }

}

说明: 留意上面的注释,如果注释掉第一句,发现一切正常,因为主对象是可以没有此属性,它的实体配置文件也基本与前面一样。而如果注释掉下面一句,将会报错,原因是“ attempted to assign id from null one-to-one property: person ”,IdCard 的实体配置文件关联了一个表,而它采取主键关联,而主键关联要依赖于person 属性的id ,如果这里注释掉,即没有了此属性,它也关联不了相应的id 。简单的说,IdCard 来要关联Person ,我们称它为从对象,而person 并不关联谁,我们称为主对象。现在只要记住,从对象关联了表(关联了主对象),必须设定它所关联的主对象属性

>> 步骤五,编写两个查询方法,一个查询主对象,主要代码:

static Person query( int id) {

       Session s = null ;

       Transaction tr = null ;

       try {

           s = HibernateUtil.getSession ();

           tr = s.beginTransaction();

           Person p = (Person) s.get(Person. class , id);

           System. out .println( " 身份证有效期:" + p.getIdCard().getValidity());

           tr.commit();

           return p;

       } finally {

           if (s != null )

              s.close();

       }

    } 

然后再在main 方法中调用此方法,并开启控制台数据库库语言显示后,可以从控制台看出查询主对象只select 一次;再增加一个查询从对象的方法,主要代码:

static IdCard query2( int id) {

       Session s = null ;

       Transaction tr = null ;

       try {

           s = HibernateUtil.getSession ();

           tr = s.beginTransaction();

           IdCard idCard = (IdCard) s.get(IdCard. class , id);

           // System. out .println( " 人的名字:" + idCard.getPerson().getName());

           // 去掉上一句注释后,发现会查询两次。

           tr.commit();

           return idCard;

       } finally {

           if (s != null )

              s.close();

       }

    }

同样在main 方法中调用此方法, 并开启控制台数据库库语言显示后。 从控制台看出也只会查询一次,但是如果去掉注释后发现会查询两次。  接着,在此例的基础上修改成外键关联。

外键关联 从表的主键并不作为外键参考主表的主键,而是将其它字段作为外键参的主键。

其实在上例的基础上,我们只需要修改IdCard.hbm.xml 配置文件即可,修改后的内容如下:

< hibernate-mapping package = "com.asm.hibernate.domain" >

    < class name = "IdCard" >

       < id name = "id" >

           < generator class = "native" />

       </ id >

       < property name = "validity" ></ property >

       < many-to-one name = "person" column = "person_id" unique = "true" />

    </ class >

</ hibernate-mapping >
说明:由于采取了外键关联,所以 这里的从表的主键将不再作为外键参考主表的主键,所以它会采取一般的方式生成主键,即<id> 生成和以前的那此相同采取“native ”方式。 另注意到< many-to-one >, 发现增加了unique 有属性,这样尽管是多对一,但能有效保证实质是一对一。  这时运行原OneToOneTest ,发现仍是和以前一样。 如果我们再修改Person 的实体配置文件<one-to-one> 如下:

< one-to-one name = "idCard" property-ref = "person" /> 特别要注意到 property-ref 属性。可以结合执行后表的结构来看。其实如果注释掉此句,其结果就是通过身份证可以查看到Person 的相关信息,但是通过Person 却不能找到身份证信息,因为Hibernate 完全依赖实体配置文件(映射文件)。注释掉当然就不能找到。 而事实上这时在OneToOne 中调用query 方法,会发现出现空指针异常。 其实在前面的关联关系中,最终都是实现了双向关联,而这里如果注释掉此句,正好成了单向关联的一个例证。