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

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

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

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

packagecom.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>

       <propertyname="name"></property>

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

    </class>

</hibernate-mapping>

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

packagecom.asm.hibernate.domain;

importjava.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>

       <propertyname="validity"></property>

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

    </class>

</hibernate-mapping>

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

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

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

packagecom.asm.hibernate.test;

public class OneToOneTest {

    public static void main(String[] args) {

       add();

    }

    static void add() {

        Sessions = 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-oneproperty: person”,IdCard的实体配置文件关联了一个表,而它采取主键关联,而主键关联要依赖于person属性的id,如果这里注释掉,即没有了此属性,它也关联不了相应的id。简单的说,IdCard来要关联Person,我们称它为从对象,而person并不关联谁,我们称为主对象。现在只要记住,从对象关联了表(关联了主对象),必须设定它所关联的主对象属性

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

static Personquery(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 IdCardquery2(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>

       <propertyname="validity"></property>

       <many-to-onename="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方法,会发现出现空指针异常。其实在前面的关联关系中,最终都是实现了双向关联,而这里如果注释掉此句,正好成了单向关联的一个例证。

相关推荐