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)在程序中设置好双方对象的关联关系,这样才能保证无论主控方是哪一方,它们的关联关系都能存入数据库。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值