现在继上一章节的一对多的映射关系讲解后,今天来讲讲多对多的映射关系把,明白了一对多,多对多感觉还是比较容易的,需要理清楚其数据库关系图,那么你就拿下了它。
1:要保存多对多的关系,两张表是不够的,需要增加第三张表来表示这种关系,来看下面的数据库关系图。
俩张中间表在数据库里面建好 ,实体类里面不需要建
为什么需要建中间表?
Users通过自己的主键在中间表中查询,因为是复合主键,所以查询到的记录有很多,而不是唯一的.
2、实体类和映射配置
Users.hbm.xml
<class name="com.zking.Pojo.Users" table="USERS">
<id name="uid" type="java.lang.String">
<column name="UID" />
<generator class="guid" />
</id>
<property name="uname" type="java.lang.String">
<column name="UNAME" />
</property>
<!-- 配置角色集合 -->
<!-- table 中间表
key column 中间表中指代本实体类的列
many-to-many column 中间表中指代集合对象的列 -->
<set name="roleList" fetch="join" table="USERSROLES" lazy="false">
<key column="uid" ></key>
<many-to-many class="com.zking.Pojo.Roles" column="rid"></many-to-many>
</set>
</class>
Roles.hbm.xml
<class name="com.zking.Pojo.Roles" table="ROLES">
<id name="rid" type="java.lang.String">
<column name="RID" />
<generator class="guid" />
</id>
<property name="rname" type="java.lang.String">
<column name="RNAME" />
</property>
<!-- 用户集合 都由roles维护-->
<set name="UserList" table="USERSROLES" cascade="save-update" inverse="true" fetch="join" >
<key column="rid"></key>
<many-to-many class="com.zking.Pojo.Roles" column="uid"></many-to-many>
</set>
<!-- 菜单集合 -->
<set name="menuList" table="ROLESMENU" cascade="save-update" inverse="true" fetch="join" >
<key column="rid"></key>
<many-to-many class="com.zking.Pojo.Menu" column="mid"></many-to-many>
</set>
</class>
Menu.hbm.xml
<class name="com.zking.Pojo.Menu" table="MENU">
<id name="mid" type="java.lang.String">
<column name="MID" />
<generator class="guid" />
</id>
<property name="mname" type="java.lang.String">
<column name="MNAME" />
</property>
<set name="mroleList" table="ROLESMENU" fetch="join">
<key column="mid"></key>
<many-to-many class="com.zking.Pojo.Roles" column="rid"></many-to-many>
</set>
</class>
设置好三个表的映射关系 要设置好和中间表的关系
3、测试类 TestMany 因为还没有任何数据,就写一个增加的例子
@Test
public void addtest() {
Users u=new Users();
//用户
u.setUname("admin");
//角色(权限)
Roles r=new Roles();
r.setRname("Admin");
Roles r1=new Roles();
r1.setRname("Super_Admin");
//菜单
Menu m=new Menu();
m.setMname("用户管理");
Menu m1=new Menu();
m1.setMname("菜单管理");
Menu m2=new Menu();
m2.setMname("修改密码");
Menu m3=new Menu();
m3.setMname("角色管理");
//互设
//用户赋予角色
u.getRoleList().add(r);
u.getRoleList().add(r1);
//角色赋予用户
r.getUserList().add(u);
r1.getUserList().add(u);
//角色加菜单
r.getMenuList().add(m);
r.getMenuList().add(m1);
r.getMenuList().add(m2);
r.getMenuList().add(m3);
r1.getMenuList().add(m);
r1.getMenuList().add(m1);
r1.getMenuList().add(m2);
r1.getMenuList().add(m3);
//菜单对应角色
m.getMroleList().add(r);
m1.getMroleList().add(r);
m2.getMroleList().add(r);
m3.getMroleList().add(r);
m.getMroleList().add(r1);
m1.getMroleList().add(r1);
m2.getMroleList().add(r1);
m3.getMroleList().add(r1);
//保存
//先保存user 才用关联性 在保存角色
session.save(u);
session.save(r1);
session.save(r);
}
我在写的过程中报了一个TransientObjectException的异常
出现该错误的原因是在保存数据的时候只保存了从表中的数据,而在该情况下并没有使用级联。
解决方法:
所以我们应该同时保存主表的数据(与之对应的类)和从表的数据(与之对应的类)。
效果图:
中间表信息就不贴图了.
4、总结
双向多对多理解了之后就会发现很简单,但是在开始学的时候,会觉得里面很绕,所以一定清楚每一步是什么,重要的是理解为什么连接表需要设置成那样。理解了你就会很轻松的学会了这个双向多对多映射关系,你一定动手自己去实现一下,其中隐藏了很多BUG,需要自己去解决。如果不动手去实践,还是会很蒙蔽的,比如级联的设置,维护的设置。
程序人生,一定要去好好的实践,祝你们都能找出bug,哈哈