天天看點

Hibernate對象關系映射-- 多對多關聯關系映射

 在關系型資料庫中,如果表與表之間存在多對多的關系,是不符合關系型資料庫設計範式的。一般需要把一個多對多關系映射為一張關聯雙方的表,這張表叫做連接配接表。

不管是單向映射還是雙向映射,多對多關系都是基于連接配接表實作的。

1、下面通過使用者(User)和角色(Role)來講解多對多的關聯映射。一個使用者(User)有多個角色(Role),一個角色對應多個使用者,是以使用者和角色之間構成多對多的關聯關系。

         實體類User和Role的資料庫表設計如下:

          CREATE  TABLE  user (

              id   INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,

              name VARCHAR(50)

          );

          CREATE  TABLE  role (

              id   INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,

              name VARCHAR(50)

          );

連接配接表user_role可以有兩中建表方式:

第一種:

CREATE TABLE  user_role (

  user_id  INT(11) NOT NULL,

  role_id   INT(11) NOT NULL,

  foreign key(user_id)  references  user (id),

  foreign key(role_id)   references  role (id)

);

第二種:

CREATE TABLE  user_role (

  user_id  INT(11) NOT NULL,

  role_id   INT(11) NOT NULL,

  foreign key(user_id)  references  user (id),

  foreign key(role_id)   references  role (id),

  primary key(user_id, role_id)

);

注意,建立連接配接表user_role時,不能另外建立一個主鍵字段。要麼像第一種方式其主鍵由資料庫自動生成,要麼像第二種方式将兩個外鍵結合聲明成一個複合主鍵。

1. 雙向的多對多關聯映射(User<--->Role)

實體類User:

public class User { 

    private int id; 

    private String name;       

    private Set roles = new HashSet();   

    public int getId() { 

        return id; 

    } 

    public void setId(int id) { 

        this.id = id; 

    } 

    public Set getRoles() { 

        return roles; 

    } 

    public void setRoles(Set roles) { 

        this.roles = roles; 

    } 

    public String getName() { 

        return name; 

    } 

    public void setName(String name) { 

        this.name = name; 

    }       

}

實體類Role:

public class Role { 

    private int id; 

    private String name; 

    private Set users = new HashSet(); 

    public Set getUsers() { 

        return users; 

    } 

    public void setUsers(Set users) { 

        this.users = users; 

    } 

    public int getId() { 

        return id; 

    } 

    public void setId(int id) { 

        this.id = id; 

    } 

    public String getName() { 

        return name; 

    } 

    public void setName(String name) { 

        this.name = name; 

    } 

}

實體類User的映射檔案:

<?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="User" table="user"> 

         <id name="id"> 

               <generator class="native"></generator> 

         </id> 

         <property name="name"></property> 

         <set name="roles" table=“user_role” cascade=“save-update” inverse = “false”> 

               <key column="user_id"></key> 

               <many-to-many class="Role" column="role_id"></many-to-many> 

         </set> 

     </class> 

</hibernate-mapping>

下面介紹下<set>元素中各屬性和子元素的含義。

name:說明在User類中,存放Role對象的集合屬性是roles。

table:說明在這個多對多關聯中,存儲關聯關系的連接配接表是user_role。

inverse:說明關聯關系的主要方,值為true或false,預設的inverse=“false”(當inverse省略時的值)。值為false的一端為主要方,來維護關聯雙方資料庫更新的同步。這個映射檔案中inverse的值為false,表明User為主導方,當User對象的資料庫表發生更新時,關聯的Role對象的資料庫表也随之更新。

cascade:說明級聯關系的模式,即操作一個對象時,是否同樣操作所關聯的對象。預設的cascade=“none”,cascade的取值可以為none、save-update、delete、all等。all:在所有的操作的情況下均進行級聯;none:在所有操作的情況下均不進行級聯操作;save-update:在執行更新操作時級聯;delete:在執行删除操作時級聯。inverse和cascade配合起來使用。

key:說明連接配接表user_role中使用外鍵user_id來關聯表user。

many-to-many:說明這個多對多關系中,另一個多方實體類是Role,并且使用連接配接表的role_id字段來關聯表role。

實體類Role的映射檔案:

<?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="Role" table="role"> 

        <id name="id"> 

             <generator class="native"></generator> 

        </id> 

        <property name="name"></property> 

        <set name="users" table="user_role"> 

             <key column="role_id"></key> 

             <many-to-many class="User" column="user_id"></many-to-many> 

        </set> 

    </class> 

</hibernate-mapping>

2.單向的多對多關聯映射(User--->Role)

對于單向的多對多關聯映射,隻需把雙向關聯的一端去掉就得到單向的多對多關聯映射。對于從User到Role的單向關聯關系,将Role一端的關聯關系去掉即可,是以實體類User和它的映射檔案不變。

實體類Role:

public class Role { 

    private int id; 

    private String name; 

    public int getId() { 

        return id; 

    } 

    public void setId(int id) { 

        this.id = id; 

    } 

    public String getName() { 

        return name; 

    } 

    public void setName(String name) { 

        this.name = name; 

    } 

}

實體類Role的映射檔案:

<?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="Role" table="role"> 

        <id name="id"> 

             <generator class="native"></generator> 

        </id> 

        <property name="name"></property> 

   </class> 

</hibernate-mapping>

3. 雙向多對多關聯應該注意的事項

(1)在雙方的映射檔案中應該都設定cascade屬性為:cascade=“save-update”,這樣如果在存儲時沒有把關聯的另一方存入,Hibernate會進行級聯存儲,避免發生存儲臨時對象的錯誤。

(2)在雙方的映射檔案中,應該設定一方的inverse屬性為inverse=“true”,另一方為inverse=“false”,這樣資料庫隻根據一方的狀态存入關聯關系,避免重複存取關聯表。

(3)在程式中設定好雙方對象的關聯關系,這樣才能保證無論主要方是哪一方,它們的關聯關系都能存入資料庫。

繼續閱讀