多对多实体映像
假设现在有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。
相关推荐
hibernate 映射关系学习入门 多对多实体映射 源码
Hibernate入门到精通,分享Hibernate的干货,带你入门,走向精通。
hibernate初学者学习入门之一对多实体映射关系源码
Hibernate入门笔记Hibernate入门笔记Hibernate入门笔记Hibernate入门笔记Hibernate入门笔记Hibernate入门笔记Hibernate入门笔记Hibernate入门笔记Hibernate入门笔记Hibernate入门笔记Hibernate入门笔记Hibernate入门...
解压后包含hibernate入门所需jar (hibernate常用jar,mysql驱动,Junit4jar)
总共分5部分:1和2为hibernate入门,3为hibernate实体映射,4为hibernate复合主键,5为hibernate实体层设计.
Hibernate入门案例,提供MyEclipse和Eclipse的项目源文件以及war文件
hibernate入门
hibernate入门小例子,采用mysql(sql-front)数据库
Hibernate入门教程.pdf
hibernate 入门详细操作步骤 包括hibernate包,实例实现文档····
Hibernate新手入门,详细讲解hibernate框架技术,以及这门技术所包含的orm思想等。
hibernate 入门经典实例 hibernate 入门经典实例 hibernate 入门经典实例 hibernate 入门经典实例 hibernate 入门经典实例
hibernate hibernate入门 hibernate学习 hibernate基础
这是一个关于hibernate入门到精通的书,希望可以帮到你
Hibernate 入门知识
hibernate官方入门教程中文版
hibernate入门源代码,最原始的入门案例。 hibernate入门源代码,最原始的入门案例。