一般的设计中,多对多关联映射需要一个中间表,hibernate会自动生成中间表,使用many-to-many标签来表示多对多的关联。在实体中,跟一对多一样,也是用集合来表示。
一、单向多对多(工程hibernate_many2many_1
)
这里我们使用用户和角色的例子,相关映射:
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>
<class name="cn.itcast.hibernate.Role" table="_role">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
</class>
</hibernate-mapping>
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="cn.itcast.hibernate">
<class name="User" table="_user">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="roles" table="_user_role">
<key column="userid"></key>
<many-to-many class="Role" column="roleid"></many-to-many>
</set>
</class>
</hibernate-mapping>
说明:可以看到多对多的情况时我们是在数据库中生成一张表专门维护映射关系。
测试:
Many2ManyTest.java
package cn.itcast.hibernate;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.hibernate.Session;
import org.junit.Test;
public class Many2ManyTest {
@Test
public void testSave1(){
Session session = null;
try{
session = HibernateUtils.getSession();
session.beginTransaction();
Role r1 = new Role();
r1.setName("数据录入人员");
session.save(r1);
Role r2 = new Role();
r2.setName("商务主管");
session.save(r2);
Role r3 = new Role();
r3.setName("大区经理");
session.save(r3);
User u1 = new User();
u1.setName("张三");
Set u1Roles = new HashSet();
u1Roles.add(r1);
u1Roles.add(r2);
u1.setRoles(u1Roles);
User u2 = new User();
u2.setName("李四");
Set u2Roles = new HashSet();
u2Roles.add(r1);
u2Roles.add(r2);
u2.setRoles(u2Roles);
User u3 = new User();
u3.setName("王五");
Set u3Roles = new HashSet();
u3Roles.add(r3);
u3Roles.add(r3);
u3.setRoles(u3Roles);
session.save(u1);
session.save(u2);
session.save(u3);
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
@Test
public void testLoad1(){
Session session = null;
try{
session = HibernateUtils.getSession();
session.beginTransaction();
User user = (User) session.load(User.class, 1);
System.out.println(user.getName());
for(Iterator iter = user.getRoles().iterator(); iter.hasNext();){
Role role = (Role) iter.next();
System.out.println(role.getName());
}
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
}
说明:虽然我们生成了一个关系表,但是维护关系只是在User这边进行维护,当然我们也可以选择在Role这边维护。此时我们在存储时应该先将不维护关系的一方(这里是Role)存储进去,然后再存储User。同样在查询的时候也一样,也是先查询出User,然后再查出Role。
二、双向多对多(工程hibernate_many2many_2
)
双向关系只需要在单向情况中的Role对象中维护一个保持用户的set集合即可。存储不变。
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>
<class name="cn.itcast.hibernate.Role" table="_role">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="users">
<key column="roleid" />
<many-to-many class="cn.itcast.hibernate.User" column="userid"/>
</set>
</class>
</hibernate-mapping>
注意:中间表的字段名一定要相同。
测试:这里就不再细说了,和单向相比,这里我们就可以双向存储和查询。同时我们也可以使用inverse属性进行关系反转,只在一方维护关系,还有可以在set标签中使用order-by属性来进行排序:
<set name="users" table="_user_role" order-by="userid">
。