`
KuangYeYaZi
  • 浏览: 52614 次
文章分类
社区版块
存档分类
最新评论

Hibernate入门之多对多实体映像

阅读更多

多对多实体映像 
 假设现在有User与Server两个类别,一个User可以被授权使用多台Server,而在Server上也记录授权使用它的使用者,就User与Server两者而言即使多对多的关系。 
 在程序设计时,基本上是不建议直接在User与Server之间建立多对多关系,这会使得User与Server相互依赖,通常会透过一个中介类别来维护两者之间的多对多关系,避免两者的相互依赖。 
 如果一定要直接建立User与Server之间的多对多关系,Hibernate也是支持的,基本上只要您了解之前介绍的几个实体映像,建立多对多关联在配置上并不困难。 
 先看一下我们设计的User与Server类别: 
User.java 

package onlyfun.caterpillar; 

import java.util.*; 

public class User { 
private long id; 
private String name; 
private Set servers = new HashSet(); 

public long getId() { 
return id; 
} 
public void setId(long id) { 
this.id = id; 
} 
public String getName() { 
return name; 
} 
public void setName(String name) { 
this.name = name; 
} 
public Set getServers() { 
return servers; 
} 

public void setServers(Set servers) { 
this.servers = servers; 
} 
} 

 Server.java 

package onlyfun.caterpillar; 

import java.util.*; 

public class Server { 
private long id; 
private String address; 
private Set users = new HashSet(); 

public long getId() { 
return id; 
} 
public void setId(long id) { 
this.id = id; 
} 
public String getAddress() { 
return address; 
} 
public void setAddress(String address) { 
this.address = address; 
} 
public Set getUsers() { 
return users; 
} 
public void setUsers(Set users) { 
this.users = users; 
} 
} 

 这边各使用HashSet来保存彼此的关系,在多对多关系映射上,我们可以建立单向或双向关系,这边直接介绍双向关系映像,并藉由设定inverse= "true",将关系的维护交由其中一方来维护,这么作的结果,在原始码的撰写上,也比较符合Java的对象关系维护,也就是双方都要设置至对方的参考。 

 首先来看看User.hbm.xml: 
User.hbm.xml 

<?xml version="1.0"?> 
<!DOCTYPE hibernate-mapping 
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" 
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> 

<hibernate-mapping> 

<class name="onlyfun.caterpillar.User" table="USER"> 

<id name="id" column="USER_ID" unsaved-value="0"> 
<generator class="increment"/> 
</id> 

<property name="name"> 
<column name="NAME" length="16" not-null="true"/> 
</property> 

<set name="servers" 
table="USER_SERVER" 
cascade="save-update"> 

<key column="USER_ID"/> 
<many-to-many class="onlyfun.caterpillar.Server" 
column="SERVER_ID"/> 
</set> 

</class> 

</hibernate-mapping>

 在数据库中,数据表之间的多对多关系是透过一个中介的数据表来完成,例如在这个例子中,USER数据表与USER_SERVER数据表是一对多,而 USER_SERVER对SERVER是多对一,从而完成USER至SERVER的多对多关系,在USER_SERVER数据表中,将会有USER_ID 与SERVER_ID共同作为主键,USER_ID作为一个至USER的外键参考,而SERVER_ID作为一个至SERVER的外键参考。 

 来看看Server.hbm.xml映射文件: 
Server.hbm.xml 

<?xml version="1.0"?> 
<!DOCTYPE hibernate-mapping 
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" 
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> 

<hibernate-mapping> 

<class name="onlyfun.caterpillar.Server" table="SERVER"> 

<id name="id" column="SERVER_ID" unsaved-value="0"> 
<generator class="increment"/> 
</id> 

<property name="address" type="string"/> 

<set name="users" 
table="USER_SERVER" 
inverse="true" 
cascade="save-update"> 

<key column="SERVER_ID"/> 
<many-to-many class="onlyfun.caterpillar.User" 
column="USER_ID"/> 
</set> 
</class> 

</hibernate-mapping> 

 设置上与User.hbm.xml是类似的,只是增加了inverse="true",表示将关系的维护交由另一端,注意我们在User与 Server的cascade都是设置为save-update,在多对多的关系中,all、delete等cascade是没有意义的,因为多对多中,并不能因为父对象被删除,而造成被包括的子对象被删除,因为可能还有其它的父对象参考至这个子对象。 

 我们使用下面这个程序来测试: 
HibernateTest.java 

import onlyfun.caterpillar.*; 
import net.sf.hibernate.*; 
import net.sf.hibernate.cfg.*; 

public class HibernateTest { 
public static void main(String[] args) throws HibernateException { 
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); 

Server server1 = new Server(); 
server1.setAddress("PC-219"); 
Server server2 = new Server(); 
server2.setAddress("PC-220"); 
Server server3 = new Server(); 
server3.setAddress("PC-221"); 

User user1 = new User(); 
user1.setName("caterpillar"); 
User user2 = new User(); 
user2.setName("momor"); 

user1.getServers().add(server1); 
user1.getServers().add(server2); 
user1.getServers().add(server3); 
server1.getUsers().add(user1); 
server2.getUsers().add(user1); 
server3.getUsers().add(user1); 

user2.getServers().add(server1); 
user2.getServers().add(server3); 
server1.getUsers().add(user2); 
server3.getUsers().add(user2); 

Session session = sessionFactory.openSession(); 
Transaction tx= session.beginTransaction(); 
session.save(user1); 
session.save(user2); 

tx.commit(); 
session.close(); 

sessionFactory.close(); 
} 
} 

 注意由于设定了inverse="true",所以必须分别设定User与Server之间的相互参考,来看看实际上数据库中是如何储存的: 

mysql> select * FROM USER; 
+---------+-------------+ 
| USER_ID | NAME | 
+---------+-------------+ 
| 1 | caterpillar | 
| 2 | momor | 
+---------+-------------+ 
2 rows in set (0.00 sec) 

mysql> select * FROM USER_SERVER; 
+-----------+---------+ 
| SERVER_ID | USER_ID | 
+-----------+---------+ 
| 1 | 1 | 
| 2 | 1 | 
| 3 | 1 | 
| 1 | 2 | 
| 2 | 2 | 
+-----------+---------+ 
5 rows in set (0.00 sec) 

mysql> select * FROM SERVER; 
+-----------+---------+ 
| SERVER_ID | address | 
+-----------+---------+ 
| 1 | PC-219 | 
| 2 | PC-221 | 
| 3 | PC-220 | 
+-----------+---------+ 
3 rows in set (0.00 sec) 
 有关于多对多更多的例子与说明,您可以参考Hibernate in Action的6.3。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics