映射关联关系
在上篇中我们已经了单个的对象,现在来添加多个对象间的关联
这里简单的添加了以下关联:一个用户(User)喜欢和参加了多个活动(Event), 他有多个Email. 一个Event被多个User参与。

1. 映射User 类
刚开始,User是很简单的:

package road2hibernate;

import java.util.Set;
import java.util.HashSet;

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

public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getFirstname() {
return firstname;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getLastname() {
return lastname;
}

}


添加映射文件 User.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=
"road2hibernate.User" table="USERS">
<id name=
"id" column="uid" type="long">
<generator class=
"increment"/>
</id>
<property name=
"age"/>
<property name=
"firstname"/>
<property name=
"lastname"/>
</class>

</hibernate-mapping>


hibernate.cfg.xml 需要加新的 resource:
<mapping resource="User.hbm.xml"/>

2. 一个 Set-based 单向关联

现在要为 User 中添加他所喜欢的 Events, 我们用一个简单的 java collection - a Set,因为它不会包含重复的元素,并且顺序与我们无关

public class User {
// ... 原有properties
private Set favouriteEvents = new HashSet();

public Set getFavouriteEvents() {
return favouriteEvents;
}

public void setFavouriteEvents(Set newFavouriteEvents) {
favouriteEvents = newFavouriteEvents;
}
// ... 原有方法
}

同时要向 User.hbm.xml 中添加:

<set name=
"favouriteEvents" table="favourite_events">
<key column=
"user_uid"/>
<many-to-many
column=
"event_uid"
class=
"road2hibernate.Event"/>
</set>


可以看到我们告诉hibernate 关于叫做favouriteEvents的 set 属性的事情
我们要考虑这个关联的类型:每个人可以有多个不同的活动爱好,一个活动也可以被多个不同的人所喜爱,所以有了 many-to-many 关联
我们需要一个关联表用于hibernate保存关联关系,这个表的名字由 set 元素的 table 属性指定,这个表至少有两列,分别保存User Event,User边的用 key 元素指定,Event边的用 many-to-many元素的 column属性指定,

3. 修改关联

向 EventManager 中添加方法:

public void addFavouriteEvent(Long userId,Long eventId){
try{
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();

User user = (User)session.load(User.class, userId);
Event event = (Event)session.load(Event.class, eventId);
user.getFavouriteEvents().add(event);

tx.commit();
HibernateUtil.closeSession();
}catch( Exception e ){
e.printStackTrace();
}
}

我们可以使用常规的collection 方法轻松修改collection,不用显式调用session.update() or session.save(), hibernate会自动侦测并保存
但如果在不同的session中load 和调用collection方法,就要显式更新,如果是在一个session 的生命周期内进行修改就可以依赖hibernate的自动脏检测
addFavouriteEvent变为这样:

private void addFavouriteEvent(Long userId, Long eventId) {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();

User user = (User) session.load(User.class, userId);
Event theEvent = (Event) session.load(Event.class, eventId);

tx.commit();
HibernateUtil.closeSession();

session = HibernateUtil.currentSession();
tx = session.beginTransaction();

user.getFavouriteEvents().add(theEvent);

session.update(user);

tx.commit();
hsqlCleanup(session);
HibernateUtil.closeSession();
}


从Hibernate 2.1后还有第三种方法,用session.lock(object, LockMode.NONE) 可以跨session

private void addFavouriteEvent(Long userId, Long eventId) {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();

User user = (User) session.load(User.class, userId);
Event theEvent = (Event) session.load(Event.class, eventId);

tx.commit();
HibernateUtil.closeSession();

session = HibernateUtil.currentSession();
tx = session.beginTransaction();

session.lock(user, LockMode.NONE);

user.getFavouriteEvents().add(theEvent);

tx.commit();
hsqlCleanup(session);
HibernateUtil.closeSession();
}


4. 值集合

通常我们也需要映射简单值类型,像a collections of Integers or a collection of Strings,下面就要为User添加一个collection of Strings来描述emails

public class User {
// ... 原有properties
private Set emails = new HashSet();

public Set getEmails() {
return emails;
}

public void setEmails(Set newEmails) {
emails = newEmails;
}
// ... 原有方法
}


同时要向 User.hbm.xml 中添加:

<set name=
"emails" table="user_emails">
<key column=
"user_uid"/>
<element column=
"email" type="string"/>
</set>

这看起来和上一次加的 set 很相似,不同的就是这回用了 element 元素,这是告诉hibernate不包含类的映射,只是一个字符串集

程序中的使用方法与上面的一样

public void addEmail( Long userId, String email ){
try{
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();

User user = (User)session.load(User.class,userId);
user.getEmails().add(email);

tx.commit();
HibernateUtil.closeSession();
}catch( Exception e ){
e.printStackTrace();
}
}


5. 双向关联

下面来映射一个双向关联,User类包含一个他所参加的Event列表,Event包含一个参加此event的user的列表,调整User Event:

public class User {
// ... 原有properties
private Set eventsJoined = new HashSet();

public Set getEventsJoined() {
return eventsJoined;
}

public void setEventsJoined(Set newEventsJoined) {
eventsJoined = newEventsJoined;
}

// ... 原有方法
}

public class Event {
// ... 原有properties

private Set participatingUsers = new HashSet();

private Set getParticipatingUsers() {
return participatingUsers;
}

private void setParticipatingUsers(Set newParticipatingUsers) {
participatingUsers = newParticipatingUsers;
}

// ... 原有方法
}


修改双方的映射文件:

Event.hbm.xml:
<set name=
"participatingUsers" table="participations">
<key column=
"event_uid"/>
<many-to-many column=
"user_uid" class="road2hibernate.User"/>
</set>

User.hbm.xml:
<set name=
"eventsJoined" table="participations" inverse="true">
<key column=
"user_uid"/>
<many-to-many column=
"event_uid" class="road2hibernate.Event"/>
</set>


可以看到所添加的内容都是我们以前常用的,只有 set 元素中的 inverse 属性没遇见过
inverse直译为反转,在hibernate 的语意中inverse 指定了关联关系中的方向,inverse="false"的为主动方,由主动方负责维护关联关系
我们的这个例子中意思为Event负责维护关联,所以只在User 中修改set 是不被持久化的,来看看如何使用:

修改Event:

public class Event {
// ... 原有properties

// Event 是主动方,修改自己的同时也要修改User
public void addParticipant(User user) {
participatingUsers.add(user);
user.getEventsJoined().add(this);
}

public void removeParticipant(User user) {
participatingUsers.remove(user);
user.getEventsJoined().remove(this);
}

// ... 原有方法
}


现在就可以使用了,在EventManager中加方法:

private void addParticipant(Long userId, Long eventId) {
try {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();

User user = (User) session.load(User.class, userId);
Event theEvent = (Event) session.load(Event.class, eventId);

theEvent.addParticipant(user);

tx.commit();
hsqlCleanup(session);
HibernateUtil.closeSession();
} catch (HibernateException e) {
throw new RuntimeException(e);
}
}

irini   2005-12-31 09:40:05 评论:0   阅读:278   引用:0

发表评论>>

署名发表(评论可管理,不必输入下面的姓名)

姓名:

主题:

内容: 最少15个,最长1000个字符

验证码: (如不清楚,请刷新)

Copyright@2008 powered by YuLog