Hibernate之关联映射

Hibernate之关联映射
在第一个hibernate小程序中我们保持了一个实体类Event到数据库的表中,这次让我们扩展一下,增加一些类的关联。
1. 映射Person类
创建Person.java
package com.iteye.hibernate.domain;

public class Person {
    private Long id;
    private int age;
    private String firstname;
    private String lastname;

    public Person() {}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getFirstname() {
		return firstname;
	}

	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}

	public String getLastname() {
		return lastname;
	}

	public void setLastname(String lastname) {
		this.lastname = lastname;
	}

}


2. 创建Person类的映射文件
Person.hbm.xml
			<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.iteye.hibernate.domain">

    <class name="Person" table="PERSON">
        <id name="id" column="PERSON_ID">
            <generator class="native"/>
        </id>
        <property name="age"/>
        <property name="firstname"/>
        <property name="lastname"/>
    </class>

</hibernate-mapping>


然后在hibernate.cfg.xml中添加一行
<mapping resource="com/iteye/hibernate/domain/Person.hbm.xml"/>

3. 添加基于Set的单向关联
这里我们通过java.util.Set向Person添加Event的关联 我们在Person类中添加如下代码
private Set events = new HashSet();

    public Set getEvents() {
        return events;
    }

    public void setEvents(Set events) {
        this.events = events;
    }

这里只是添加了一个Person到Event的单向关联,如果需要你可以在Event中添加Event到Person的关联,但这通常不是必须的。这样的一个关联我们叫做多对多的关联many-to-many。因此我们需要修改Person的映射文件
<set name="events" table="PERSON_EVENT">
        	<key column="PERSON_ID"/>
        	<many-to-many column="EVENT_ID" class="Event"/>
 </set>

通常对于一个n:m的关联,我们需要一个中间表。这个表的每一行都是标示一个Person到一个Event的链接。表的名称使用table属性来指定。而表的主键在Person这表通过key来指定,而在Event这边通过many-to-many来指定
表之间的关系如下

4. 我们在EventManager中添加方法来实现数据的关联
	private void addPersonToEvent(Long personId, Long eventId) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        Person aPerson = (Person) session.load(Person.class, personId);
        Event anEvent = (Event) session.load(Event.class, eventId);
        aPerson.getEvents().add(anEvent);

        session.getTransaction().commit();
    }

这里我们不用调用save或者update方法,hibernate会自动检测到集合已经改变,自动进行更新,这叫做自动脏数据检测

你可以在不同的工作单元里面加载person和Event。或者你可以更改一个不是持久状态的对象(关于在Hibernate中对象的几种状态,在最后进行说明),你也可以修改一个托管的对象,可以参考一下代码
		private void addPersonToEvent(Long personId, Long eventId) {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        Person aPerson = (Person) session
                .createQuery("select p from Person p left join fetch p.events where p.id = :pid")
                .setParameter("pid", personId)
                .uniqueResult(); // Eager fetch the collection so we can use it detached
        Event anEvent = (Event) session.load(Event.class, eventId);
        session.getTransaction().commit();
        // End of first unit of work
        aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detache
        // Begin second unit of work
        Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
        session2.beginTransaction();
        session2.update(aPerson); // Reattachment of aPerson
        session2.getTransaction().commit();
    }

调用update通过绑定到一个新的工作单元使一个托管的对象重新持久化,以便于你所做的改变可以存储到数据库
值的集合

让我们想Person类中添加一个邮箱地址的集合
private Set emailAddresses = new HashSet();

    public Set getEmailAddresses() {
        return emailAddresses;
    }

    public void setEmailAddresses(Set emailAddresses) {
        this.emailAddresses = emailAddresses;

为Person添加映射
	<set name="emailAddresses" table="PERSON_EMAIL_ADDR">
        	<key column="PERSON_ID"/>
        	<element  type="string" column="EMAIL_ADDR"/>
        </set>

和之前不同的是我们通过element来告诉hibernate我们的set中包含的是一些值而不是另外一个实体的引用。
这里的类型string是一个hibernate的类型转换器。Table属性依然是用来指定表名,key用来指定一个外键

				private void addEmailToPerson(Long personId, String emailAddress) {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        Person aPerson = (Person) session.load(Person.class, personId);
        // adding to the emailAddress collection might trigger a lazy load of the collection
        aPerson.getEmailAddresses().add(emailAddress);

        session.getTransaction().commit();
    }


添加双向的关联

你同样可以为person和event指定一个双向的关联,数据库的结构没有任何改变,依然是一个多对对的关联。
首先添加一个集合到Event类
	private Set participants = new HashSet();

	public Set getParticipants() {
		return participants;
	}

	public void setParticipants(Set participants) {
		this.participants = participants;
	}
然后修改mapping文件

	<set name="participants" table="PERSON_EVENT" inverse="true">
            <key column="EVENT_ID"/>
            <many-to-many column="PERSON_ID" class="Person"/>
        </set>

依然是一个set,和以前介绍的一样,唯一不同的是多了inverse="true"
这个是告诉hibernate从另一边也就是Person找到两者之间的关联



猜你喜欢

转载自hellogava.iteye.com/blog/1570465