前面两节我们讲到了一对一的关系,一对多,多对一的关系,相对来说,是比较简单的,但有时,我们也会遇到多对多的关系,比如说:角色与权限的关系,就是典型的多对多的关系,因此,我有必要对这种关系详解,以便大家一起学习。下面来看例子:

首先我们必须建立二者的vo:

public class Role implements Serializable {//这是role对象
private Integer rid;
private String rdesc;
private String rname; private Set<Function> funs = new HashSet<Function>();
....get,set方法已省略
//这里重新写hashcode()与equals()是因为在set集合中不允许有重复的对象,也防止在添加时会重复添加相同的数据
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((rdesc == null) ? 0 : rdesc.hashCode());
result = prime * result + ((rname == null) ? 0 : rname.hashCode());
return result;
} @Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Role other = (Role) obj;
if (rdesc == null) {
if (other.rdesc != null)
return false;
} else if (!rdesc.equals(other.rdesc))
return false;
if (rname == null) {
if (other.rname != null)
return false;
} else if (!rname.equals(other.rname))
return false;
return true;
}
}
public class Function implements Serializable {//function的vo,也就是权限

    private Integer fid;
private String fname;
private String fdesc; private Set<Role> roles = new HashSet<Role>(); //get,set方法已省略,对hashcode等方法如上同
}

下面我们配置各自的mapping文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.ysq.vo" >
<class name="Role" table="y_role">
<id name="rid">
<generator class="sequence">
<param name="sequence">dept_seq</param>
</generator>
</id> <property name="rname" length="20"></property>
<property name="rdesc" length="20"></property> <!-- *****cascade="save-update":如果设置成all,删除的时候,会把另外中的数据删除了
--><!-- role对中间表可以设为一对多情况 table是多对多中的中间表名 -->
<set name="funs" table="y_role_fun" fetch="join" cascade="save-update" lazy="false">
<key column="rid"></key><!-- 当前这个类所对应的表的中间表的外键字段 -->
<many-to-many class="Function" column="fid"></many-to-many>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.ysq.vo" >
<class name="Function" table="y_fun">
<id name="fid">
<generator class="sequence">
<param name="sequence">dept_seq</param>
</generator>
</id>
<property name="fname" length="20"/>
<property name="fdesc" length="20"/>
<!-- 权限表对中间表相当于一对多的情况 使用控制反转 使对中间表的权限交给role表来控制-->
<set name="roles" table="y_role_fun" inverse="true">
<key column="fid"></key><!-- y_fun在中间表所对应的外键 -->
<many-to-many class="Role" column="rid"></many-to-many>
</set>
</class>
</hibernate-mapping>

编写测试类:

public class many_to_many_Test {

    /**
* 如果不需要控制反转的话,不能设置双向关联,不然会在中间表中添加重复字段
*/
@Test
public void addRole(){
Role role = new Role();
Function fun = new Function();
Function fun1 = new Function();
Function fun2 = new Function(); role.setRname("经理");
role.setRdesc("公司上下"); fun.setFname("用户添加");
fun.setFdesc("用户添加");
fun1.setFname("用户删除");
fun1.setFdesc("用户删除");
fun2.setFname("用户修改");
fun2.setFdesc("用户修改"); Session session = SessionFactoryUtils.getSession();
Transaction tr = session.beginTransaction();
tr.begin(); //设置单向关联
/*fun.getRoles().add(role);
fun1.getRoles().add(role);
fun2.getRoles().add(role); *///如果设置了控制反转,可以不设置双向关联 role.getFuns().add(fun);
role.getFuns().add(fun1);
role.getFuns().add(fun2); session.save(role); tr.commit();
session.close();
} /**
* 删除某一角色的中的某一种权限:先查询该角色所拥有的权限,然后for遍历删除对应的权限
*/
@Test
public void deleteRole(){
Session session = SessionFactoryUtils.getSession();
Transaction tx = session.beginTransaction(); try {
tx.begin(); Role role = (Role)session.get(Role.class, 9);
Set<Function> funs = role.getFuns();
/*for (Iterator iterator = funs.iterator(); iterator.hasNext();) {
Function function = (Function) iterator.next();
if(function.getFid() == 10){
iterator.remove();
break;
}
} */
for (Function function : funs) {
//删除set中对应的权限
if(function.getFid() == 11){
funs.remove(function);//移除set中的此权限
break;//注意:这里必须要break,这与set集合中删除时游标有关
}
}
//在重新更新此角色的权限列表
role.setFuns(funs);
session.update(role); tx.commit();
} catch (Exception e) {
// TODO: handle exception
tx.rollback();
e.printStackTrace();
}finally{
session.close();
}
}
/**
* join fetch 【有set集合,不能用join fetch】
*/
@Test
public void findRole(){
Session session = SessionFactoryUtils.getSession();
List<Role> roles = session.createQuery("from Role").list();
session.close(); for (Role role : roles) {
System.out.println(role.getRname());
if(role.getFuns().size() > 0){
for (Function fun: role.getFuns()) {
System.out.println(fun.getFname());
}
}
}
}
}

Hibernate中的多对多关系详解(3)​的更多相关文章

  1. Hibernate中的一对多关系详解(2)

    一对多的关系:例如,部门对员工,一个部门可以有多个员工 多对一的关系:例如,员工对部门,多个员工属于一个部门,并且每个员工只能属于一个部门 那么一对多.多对一在数据库中的是怎样表示的呢?好多话都不说了 ...

  2. laravel中的多对多关系详解

    数据表之间是纵横交叉.相互关联的,laravel的一对一,一对多比较好理解,官网介绍滴很详细了,在此我就不赘述啦,重点我记下多对多的关系 一种常见的关联关系是多对多,即表A的某条记录通过中间表C与表B ...

  3. Hibernate一对多和多对一关系详解 (转载)

    :双向一对多关系,一是关系维护端(owner side),多是关系被维护端(inverse side).在关系被维护端需要通过@JoinColumn建立外键列指向关系维护端的主键列.     publ ...

  4. Qt中QGraphics类坐标映射关系详解

    1.Item(图元)坐标:属于局部坐标,通常以图元中心为原点(中心对称),非中心对称类,比如dialog类,一般以左上角为原点,正方向x朝右,y朝下. 2.setPos的坐标是父类坐标系的坐标,一般对 ...

  5. hibernate集合映射inverse和cascade详解

    hibernate集合映射inverse和cascade详解   1.到底在哪用cascade="..."? cascade属性并不是多对多关系一定要用的,有了它只是让我们在插入或 ...

  6. slf4j log4j logback关系详解和相关用法

    slf4j log4j logback关系详解和相关用法 写java也有一段时间了,一直都有用slf4j log4j输出日志的习惯.但是始终都是抱着"拿来主义"的态度,复制粘贴下配 ...

  7. 【转】UML类图与类的关系详解

    UML类图与类的关系详解   2011-04-21 来源:网络   在画类图的时候,理清类和类之间的关系是重点.类的关系有泛化(Generalization).实现(Realization).依赖(D ...

  8. C#中的Linq to Xml详解

    这篇文章主要介绍了C#中的Linq to Xml详解,本文给出转换步骤以及大量实例,讲解了生成xml.查询并修改xml.监听xml事件.处理xml流等内容,需要的朋友可以参考下 一.生成Xml 为了能 ...

  9. UML类图与类的关系详解

    摘自:http://www.uml.org.cn/oobject/201104212.asp UML类图与类的关系详解 2011-04-21 来源:网络 在画类图的时候,理清类和类之间的关系是重点.类 ...

随机推荐

  1. win8笔记本无法搜索wifi信号找不到WLAN该 wifi共享特别注意的服务

    WlansvcWLAN AutoConfigWLANSVC 服务提供配置.发现.连接.断开与 IEEE 802.11 标准定义的无线局域网(WLAN)的连接所需的逻辑.它还包含将计算机变成软件访问点的 ...

  2. oracle15 pl/sql 分页

    PL/SQL分页 编写分页过程 无返回值的存储过程 古人云:欲速则不达,为了让大家伙比较容易接受分页过程编写,我还是从简单到复杂,循序渐进的给大家讲解.首先是掌握最简单的存储过程,无返回值的存储过程: ...

  3. linux 启动流程图

    http://blog.163.com/x_ares/blog/static/101548562011710112613165/ http://baogf92.blog.51cto.com/10869 ...

  4. C++使用Json作为数据包装格式的通信

    出处:http://adebugger.cn/2009/11/cpp-json-data-communication/ http://hi.baidu.com/tibelf/item/6be2accd ...

  5. Retrofit2源码分析(一)

    本文将顺着构建请求对象→构建请求接口→发起同步/异步请求的流程,分析retrofit2是如何实现的. 组成部分 Retrofit2源码主要分为以下几个部分: retrofit retrofit-ada ...

  6. Nginx性能统计模块http_stub_status_module使用

    1.进入nginx源码目录,重新配置编译参数 ./configure --prefix=/usr/local/nginx/ --with-http_stub_status_module 2.重新编译安 ...

  7. table完美css样式,table的基本样式,table样式

    table完美css样式,table的基本样式,table样式 >>>>>>>>>>>>>>>>> ...

  8. java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

    在使用Fragment的过程中,常常会遇到在Activity的onSaveInstanceState方法调用之后,操作commit或者popBackStack而导致的crash. 因为在onSaveI ...

  9. 设计webapp的新思路

    一般设计移动应用有3中方式:原生.脚本.混合:今天我们用另一种方式实现. 我叫它:响应式网页webApp 一.具体构架思路是这样的: 客户端:Android手机 Android手机中有控件WebVie ...

  10. c语言_链表实例讲解(两个经典例子)

    建立一个学生成绩的线性链表,对其实现插入,删除,输出,最后销毁. demo1 // lianbiao.cpp : Defines the entry point for the console app ...