Hibernate多對多示例

xuehongliang發表於2007-06-29

假設現在有User與Server兩個類別,一個User可以被授權使用多臺Server,而在Server上也記錄授權使用它的使用者,就User與Server兩者而言即使多對多的關係。

在程式設計時,基本上是不建議直接在User與Server之間建立多對多關係,這會使得User與Server相互依賴,通常會透過一個中介類別來維護兩者之間的多對多關係,避免兩者的相互依賴。

如果一定要直接建立User與Server之間的多對多關係,Hibernate也是支援的,基本上只要您瞭解之前介紹的幾個實體對映,建立多對多關聯在配置上並不困難。

先看一下我們設計的User與Server類別:

java 程式碼
  1. package onlyfun.caterpillar;
  2. import java.util.*;
  3. public class User {
  4. private long id;
  5. private String name;
  6. private Set servers = new HashSet();
  7. public long getId() {
  8. return id;
  9. }
  10. public void setId(long id) {
  11. this.id = id;
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. public Set getServers() {
  20. return servers;
  21. }
  22. public void setServers(Set servers) {
  23. this.servers = servers;
  24. }
  25. }
java 程式碼
  1. package onlyfun.caterpillar;
  2. import java.util.*;
  3. public class Server {
  4. private long id;
  5. private String address;
  6. private Set users = new HashSet();
  7. public long getId() {
  8. return id;
  9. }
  10. public void setId(long id) {
  11. this.id = id;
  12. }
  13. public String getAddress() {
  14. return address;
  15. }
  16. public void setAddress(String address) {
  17. this.address = address;
  18. }
  19. public Set getUsers() {
  20. return users;
  21. }
  22. public void setUsers(Set users) {
  23. this.users = users;
  24. }
  25. }

這邊各使用HashSet來儲存彼此的關係,在多對多關係對映上,我們可以建立單向或雙向關係,這邊直接介紹雙向關係對映,並藉由設定inverse="true",將關係的維護交由其中一方來維護,這麼作的結果,在原始碼的撰寫上,也比較符合Java的物件關係維護,也就是雙方都要設定至對方的參考。

首先來看看User.hbm.xml:

xml 程式碼
  1. xml version="1.0"?>
  2. PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
  3. ">
  4. <hibernate-mapping>
  5. <class name="onlyfun.caterpillar.User" table="USER">
  6. <id name="id" column="USER_ID" unsaved-value="0">
  7. <generator class="increment"/>
  8. id>
  9. <property name="name">
  10. <column name="NAME" length="16" not-null="true"/>
  11. property>
  12. <set name="servers"
  13. table="USER_SERVER"
  14. cascade="save-update">
  15. <key column="USER_ID"/>
  16. <many-to-many class="onlyfun.caterpillar.Server"
  17. column="SERVER_ID"/>
  18. set>
  19. class>
  20. 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對映檔案:

xml 程式碼
  1. xml version="1.0"?>
  2. PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
  3. ">
  4. <hibernate-mapping>
  5. <class name="onlyfun.caterpillar.Server" table="SERVER">
  6. <id name="id" column="SERVER_ID" unsaved-value="0">
  7. <generator class="increment"/>
  8. id>
  9. <property name="address" type="string"/>
  10. <set name="users"
  11. table="USER_SERVER"
  12. inverse="true"
  13. cascade="save-update">
  14. <key column="SERVER_ID"/>
  15. <many-to-many class="onlyfun.caterpillar.User"
  16. column="USER_ID"/>
  17. set>
  18. class>
  19. hibernate-mapping>

設定上與User.hbm.xml是類似的,只是增加了inverse="true",表示將關係的維護交由另一端,注意我們在User與Server的cascade都是設定為save-update,在多對多的關係中,all、delete等cascade是沒有意義的,因為多對多中,並不能因為父物件被刪除,而造成被包括的子物件被刪除,因為可能還有其它的父物件參考至這個子物件。

我們使用下面這個程式來測試:

java 程式碼
  1. import onlyfun.caterpillar.*;
  2. import net.sf.hibernate.*;
  3. import net.sf.hibernate.cfg.*;
  4. public class HibernateTest {
  5. public static void main(String[] args) throws HibernateException {
  6. SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
  7. Server server1 = new Server();
  8. server1.setAddress("PC-219");
  9. Server server2 = new Server();
  10. server2.setAddress("PC-220");
  11. Server server3 = new Server();
  12. server3.setAddress("PC-221");
  13. User user1 = new User();
  14. user1.setName("caterpillar");
  15. User user2 = new User();
  16. user2.setName("momor");
  17. user1.getServers().add(server1);
  18. user1.getServers().add(server2);
  19. user1.getServers().add(server3);
  20. server1.getUsers().add(user1);
  21. server2.getUsers().add(user1);
  22. server3.getUsers().add(user1);
  23. user2.getServers().add(server1);
  24. user2.getServers().add(server3);
  25. server1.getUsers().add(user2);
  26. server3.getUsers().add(user2);
  27. Session session = sessionFactory.openSession();
  28. Transaction tx= session.beginTransaction();
  29. session.save(user1);
  30. session.save(user2);
  31. tx.commit();
  32. session.close();
  33. sessionFactory.close();
  34. }
  35. }

注意由於設定了inverse="true",所以必須分別設定User與Server之間的相互參考,來看看實際上資料庫中是如何儲存的:

select * FROM USER

+---------+-------------+
| USER_ID | NAME |
+---------+-------------+
| 1 | caterpillar |
| 2 | momor |
+---------+-------------+

select * FROM USER_SERVER

+-----------------+--------------+
| SERVER_ID | USER_ID |
+-----------------+--------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 1 | 2 |
| 2 | 2 |
+-----------------+--------------+

select * FROM SERVER

+-----------------+------------+
| SERVER_ID | address |
+-----------------+------------+
| 1 | PC-219 |
| 2 | PC-221 |
| 3 | PC-220 |
+-----------------+-------------+

[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/800861/viewspace-922099/,如需轉載,請註明出處,否則將追究法律責任。

相關文章