Hibernate的多对多关联关系

来源:互联网 发布:淘宝实木家具店 编辑:程序博客网 时间:2024/06/03 01:26

假如一个公司的组织结构发展到一定阶段,原来所定义的一个用户只属于一个部门这种需求将会发生变化,一个用户(员工)可能担任多个角色,比如,一个员工可能既是人力资源部主管、又是财务部的总监,一个人属于多个部门是再正常不过的了!那此时,一个用户可以同时多个部门,一个部门下面又有多个员工,那员工与部门之间就是一种多对多关联关系。再如,用户跟角色之间的关联关系,一个用户他可能是属于系统管理员,也可能是属于某一个项目的项目经理,也可能他是信息发布管理员等,一个用户可以同时拥有多个角色。每个角色可以有多个用户,那用户跟角色之间是一种多对多的关联关系。
    下面,将以用户跟角色的关联关系来介绍一下多对多的关联关系。
    物理数据模型如下图所示:
略

从上图我们可以看出,对于建立多对多关联关系时,我们需要建立中间表,中间表是由一个USER_ID跟一个ROLE_ID组成一个联合组件。

建表的SQL:

程序代码
/*==============================================================*/
/* DBMS name:      MySQL 5.0                                    */
/* Created on:     2008-4-23 12:32:13                           */
/*==============================================================*/
drop table if exists T_ROLE;

drop table if exists T_ROLE_USER;

drop table if exists T_USER;

/*==============================================================*/
/* Table: T_ROLE                                                */
/*==============================================================*/
create table T_ROLE
(
   ID                   int not null auto_increment,
   ROLE_NAME            VARCHAR(20) not null,
   DESCRIPTION          VARCHAR(255),
   primary key (ID)
);

/*==============================================================*/
/* Table: T_ROLE_USER                                           */
/*==============================================================*/
create table T_ROLE_USER
(
   USER_ID              INT not null,
   ROLE_ID              INT not null,
   primary key (USER_ID, ROLE_ID)
);

/*==============================================================*/
/* Table: T_USER                                                */
/*==============================================================*/
create table T_USER
(
   ID                   INT not null auto_increment,
   USER_NAME            VARCHAR(20) not null,
   LOGINID              VARCHAR(20) not null,
   PASSWORD             VARCHAR(32) not null,
   primary key (ID)
);

alter table T_ROLE_USER add constraint FK_Reference_1 foreign key (USER_ID)
      references T_USER (ID) on delete restrict on update restrict;

alter table T_ROLE_USER add constraint FK_Reference_2 foreign key (ROLE_ID)
      references T_ROLE (ID) on delete restrict on update restrict;



初始化数据:
 程序代码

insert into t_user (user_name,loginId,password) values('哲哲','zizz','admin');
insert into t_role (role_name,description) values('系统管理员','拥有系统的所有操作权限');



    对象模型如下图所示:

他们之间的关联关系为:用户对象有一个成员,成员类型是一个Set,该集合里面包含了用户所属的组。

User.java

程序代码
package zizz.model;

import java.io.Serializable;
import java.util.Set;

/**
* 该对象是针对着数据库的T_USER表.
*
* <a href="http://www.suneca.com">ZIZZ</a>
*
* Create-Time:Apr 21, 2008 9:53:58 PM
*/

public class User implements Serializable {

    /**
     * serialVersionUID
     */

    private static final long serialVersionUID = 1L;

    private int id;
    
    private String userName;
    
    private String loginId;
    
    private String password;
    
    private Set<Role> roles;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getLoginId() {
        return loginId;
    }

    public void setLoginId(String loginId) {
        this.loginId = loginId;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }
}



User.hbm.xml

程序代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="zizz.model">
    <class name="User" table="T_USER">
        <id name="id" column="ID">
            <generator class="increment" />
        </id>

        <property name="userName" column="USER_NAME" />
        <property name="loginId" column="LOGINID" />
        <property name="password" column="PASSWORD" />      
        
        <set name="roles" inverse="false" cascade="all" lazy="true" table="T_ROLE_USER">
            <key column="USER_ID"/>
            <many-to-many column="ROLE_ID" class="Role"/>
        </set>
    </class>
</hibernate-mapping>



Role.java

程序代码
package zizz.model;

import java.io.Serializable;
import java.util.Set;

/**
* 角色对象,该对象映射为数据库T_ROLE表.
*
* <a href="http://www.suneca.com">ZIZZ</a>
*
* Create-Time:Apr 23, 2008 4:19:31 PM
*/

public class Role implements Serializable{

    /**
     * serialVersionUID
     */

    private static final long serialVersionUID = 1L;

    private int id;
    
    private String roleName;
    
    private String description;
    
    private Set<User> users;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Set<User> getUsers() {
        return users;
    }

    public void setUsers(Set<User> users) {
        this.users = users;
    }
    
}



Role.hbm.xml

程序代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="zizz.model">
    <class name="Role" table="T_ROLE">
        <id name="id" column="ID">
            <generator class="increment" />
        </id>

        <property name="roleName" column="ROLE_NAME" />
        <property name="description" column="DESCRIPTION" />    
        
        <set name="users" inverse="false" cascade="all" lazy="true"  table="T_ROLE_USER">
            <key column="ROLE_ID"/>
            <many-to-many column="USER_ID" class="User"/>
        </set>          
    </class>
</hibernate-mapping>



假如我们的数据库T_USER表当中有一条数据,ID为1;T_ROLE当中有一条数据,ID也为1,现在我们想指派角色给用户,那我们可以使用以下的方式实现:
ManyToMany.java

程序代码
package zizz.test;

import zizz.dao.RoleDAO;
import zizz.dao.UserDAO;
import zizz.dao.hibernate.RoleDAOHibernate;
import zizz.dao.hibernate.UserDAOHibernate;
import zizz.model.Role;
import zizz.model.User;

/**
* 测试多对多.
*
* <a href="http://www.suneca.com">ZIZZ</a>
*
* Create-Time:Apr 23, 2008 4:21:53 PM
*/

public class ManyToMany {
    
    public static void main(String[] args){
        ManyToMany.assignRoleToUser();
    }
    
    public static void assignRoleToUser(){
        /*因为插入T_USER、以及T_ROLE表第一条数据,id都为1*/
        /* 得到角色 */
        RoleDAO rdao = new RoleDAOHibernate();
        Role role = rdao.findRoleById(1);
        /* 得到用户 */
        UserDAO udao = new UserDAOHibernate();
        User user = udao.findUserById(1);
        
        /* 将角色指派给用户 */
        user.getRoles().add(role);
        udao.updateUser(user);
    }

}



系统控制台打印的SQL信息:

程序代码
Hibernate: select user0_.ID as ID0_0_, user0_.USER_NAME as USER2_0_0_, user0_.LOGINID as LOGINID0_0_, user0_.PASSWORD as PASSWORD0_0_ from T_USER user0_ where user0_.ID=?
Hibernate: select roles0_.USER_ID as USER1_1_, roles0_.ROLE_ID as ROLE2_1_, role1_.ID as ID2_0_, role1_.ROLE_NAME as ROLE2_2_0_, role1_.DESCRIPTION as DESCRIPT3_2_0_ from T_ROLE_USER roles0_ left outer join T_ROLE role1_ on roles0_.ROLE_ID=role1_.ID where roles0_.USER_ID=?
Hibernate: insert into T_ROLE_USER (USER_ID, ROLE_ID) values (?, ?)



在维护多对多关联关系的时候,必须保证前后的SESSION是同一个,否则,将会出问题!将会抛出以下的错误信息:

程序代码
Exception in thread "main" org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions
    at org.hibernate.collection.AbstractPersistentCollection.setCurrentSession(AbstractPersistentCollection.java:410)
    at org.hibernate.event.def.OnUpdateVisitor.processCollection(OnUpdateVisitor.java:40)
    at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:101)
    at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:61)
    at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:55)
    at org.hibernate.event.def.AbstractVisitor.process(AbstractVisitor.java:123)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:267)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:216)
    at org.hibernate.event.def.DefaultUpdateEventListener.performSaveOrUpdate(DefaultUpdateEventListener.java:33)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
    at org.hibernate.impl.SessionImpl.fireUpdate(SessionImpl.java:559)
    at org.hibernate.impl.SessionImpl.update(SessionImpl.java:547)
    at org.hibernate.impl.SessionImpl.update(SessionImpl.java:539)
    at zizz.dao.hibernate.UserDAOHibernate.updateUser(UserDAOHibernate.java:53)
    at zizz.test.ManyToMany.assignRoleToUser(ManyToMany.java:34)
    at zizz.test.ManyToMany.main(ManyToMany.java:20)