多对多关联映射通常采用第三方表,这张表存储了他们之间的关联关系。
一、单向多对多关联映射:
用户和角色属于多对对关系,一个用户可以拥有多个角色,一个角色也可以属于多个用户。
public class User {
private int userid;
private String username;
private Set roles;
getter and setter..
}
public class Role {
private int roleid;
private String rolename;
getter & setter
}
User.hbm.xml:
<?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 package="com.wyx.hibernate"> <class name="User" table="t_User"> <id name="userid"> <generator class="native"/> </id> <property name="username"/> <set name="roles" table="t_User_Role" cascade="all"> <key column="userid" /> <many-to-many class="Role" column="roleid"/> </set> </class> </hibernate-mapping>
set标签中的name指的是user的关联关系字段,set代表了中间表,用table指定中间表的名字,用key 的column属性作为外键指向user表的userid,many-to-mang的column作为外键指向role表的roid,构成了复合主键(由userid和roleid构成的)。
Role.hbm.xml:
<?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 package="com.wyx.hibernate"> <class name="Role" table="t_Role"> <id name="roleid"> <generator class="native"/> </id> <property name="rolename"/> </class> </hibernate-mapping>
测试一对多save,从user方存储:
public void testSave(){
Session session = HibernateUtils.getSession();
try {
session.beginTransaction();
Role role1 = new Role();
role1.setRolename("程序员");
//session.save(role1);
Role role2 = new Role();
role2.setRolename("架构师");
//session.save(role2);
Set roles = new HashSet<Role>();
roles.add(role1);
roles.add(role2);
User user =new User();
user.setUsername("冰吼");
user.setRoles(roles);
session.save(user);
session.getTransaction().commit();
} catch (HibernateException e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
打印输出:
Hibernate: insert into t_User (username) values (?)
Hibernate: insert into t_Role (rolename) values (?)
Hibernate: insert into t_Role (rolename) values (?)
Hibernate: insert into t_User_Role (userid, roleid) values (?, ?)
Hibernate: insert into t_User_Role (userid, roleid) values (?, ?)
测试一对多load,从user一方存储:
public void testLoad(){
Session session = HibernateUtils.getSession();
try {
session.beginTransaction();
User user = (User)session.load(User.class, 1);
Set<Role> roles = user.getRoles();
System.out.println("user.username = " + user.getUsername());
for(Iterator<Role> iter = roles.iterator(); iter.hasNext();){
Role role = iter.next();
System.out.println("user.role.rolename = " + role.getRolename());
}
session.getTransaction().commit();
} catch (HibernateException e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
打印输出:
Hibernate: select user0_.userid as userid1_0_, user0_.username as username1_0_ from t_User user0_ where user0_.userid=?
user.username = 冰吼
Hibernate: select roles0_.userid as userid1_, roles0_.roleid as roleid1_, role1_.roleid as roleid0_0_, role1_.rolename as rolename0_0_ from t_User_Role roles0_ left outer join t_Role role1_ on roles0_.roleid=role1_.roleid where roles0_.userid=?
user.role.rolename = 架构师
user.role.rolename = 程序员
二、双向多对多关联映射:
双向多对多关联映射与单向的基本一致,不同之处就是在双发都加入了set集合来保存关联关系,但是在存储字段的时候,最好指定根据一方来添加,两边都存储容易造成混乱,在其中的一方映射文件的set标签中加入inverse = "true",将控制权交给另一方处理。【inverse属性只能应用于一对多双向关联、多对多双向关联】
修改Role.java:
package com.wyx.hibernate;
import java.util.Set;
public class Role {
private int roleid;
private String rolename;
private Set users;
getter & setter...
}
修改Role.hbm.xml:
<?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 package="com.wyx.hibernate"> <class name="Role" table="t_Role"> <id name="roleid"> <generator class="native"/> </id> <property name="rolename"/> <set name="users" table="t_User_Role" inverse="true" cascade="all" order-by="userid"> <key column="roleid"/> <many-to-many class="User" column="userid"/> </set> </class> </hibernate-mapping>
/**
* save role casecad user
*/
public void testSave(){
Session session = HibernateUtils.getSession();
try {
session.beginTransaction();
User user1 =new User();
user1.setUsername("冰吼");
User user2 =new User();
user2.setUsername("蓝胖");
Set users = new HashSet<User>();
users.add(user1);
users.add(user2);
Role role = new Role();
role.setRolename("架构师");
role.setUsers(users);
session.save(role);
session.getTransaction().commit();
} catch (HibernateException e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
加入了inserse = "true",就不能从Role端存入数据,用以上测试方法存数据,中间表是不能存入数据的,但是去掉inserse就可以,但为了防止出错,还是加inverse由指定固定一方控制添加比较好。