【Hibernate步步为营】--多对多映射具体解释
上篇文章具体讨论了一对多映射,在一对多映射中单向的关联映射会有非常多问题,所以不建议使用假设非要採用一对多的映射的话能够考虑使用双向关联来优化之间的关系,一对多的映射事实上质上是在一的一端使用<many-to-one>标签来标明它们之间的关系,另外还须要在一的一端的对象中使用set标明集合映射。
一、单向多对多
仍然依照前几篇的文章格式来讨论。首先来看对象之间的关系,单向的多对多关系是两个对象之间发生的,比方在人和职位之间,一个人能够有多个职位,并且一个职位也能够由多人来负责,所以它们之间就形成了多对多的关系,另外这样的单向性是指仅仅能在一端来查询获取还有一端的内容。
另外由于是多对多之间的关系,所以在生成关系模型时会生成对象之间的关联表。实际它们之间的关系的是关联表,详细的对象模型例如以下:
上面已经说过多对多的关系会生成一个关联表。在关联表中来维护之间的关系。所以相应的关系模型中会有一个关系表,这个关系表中存放着两个关系表的主键,而且关系表的主键是另外两张表的主键的组合。例如以下图:
1.1、映射
上面的关系模型中会生成一个关系表。所以在映射中要编写相应的属性,由于是单向的关联关系所以基本的映射关系是在映射的原方向加入的,相应的上面的关系模型上就是在T_user中加入多对多映射的关系。
1.1.1 User.hbm.xml
文件里要使用<many-to-many>标签,而且在标签中加入上相应的列关系,由于你要让两个对象中都要清楚它们之间的映射是怎样使用的。而且在生成的关系表中哪一列是相应的自己的外键,所以要在该标签中指明,另外在<set>标签中加入table属性会指明要生成新表,以下的演示样例中加入了t_user_role,所以会生成新的关联表。
<?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="com.src.hibernate.User" table="t_user">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="roles" table="t_user_role">
<key column="user_id"></key>
<many-to-many class="com.src.hibernate.Role" column="role_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
1.1.2 Role.hbm.xml
由于是单向的关系,所以在该映射文件里就不须要加入多余的标签来维护关系了,它的内部代码也会非常easy,相应的映射代码例如以下:
<?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="com.src.hibernate.Role" table="t_role">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
</class>
</hibernate-mapping>
1.2、类文件
类文件里代码的编写要和映射文件里配置的同样。它们之间是相互相应的,在user中由于使用了<set>映射,所以在相应的类文件里也要加入Haseset来标明之间的映射关系。
1.2.1 User.java
类代码没有什么好讨论的了,里面的内容和前几篇文章的大致同样,除了主要的属性和方法外还须要加入相应的HashSet。
package com.src.hibernate;
import java.util.Set; public class User {
//ID号
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
} //名称
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
} //角色集合
private Set roles;
public Set getRoles() {
return roles;
}
public void setRoles(Set roles) {
this.roles = roles;
}
}
1.2.2 Role.java
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhbmdfeGlueGl1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
package com.src.hibernate;
public class Role {
//id标示
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
//名称
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
生成的表结构例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhbmdfeGlueGl1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
1.3、操作
1.3.1 插入操作
public void testSave(){
Session session=null;
try{
//创建session对象
session=HibernateUtils.getSession();
//开启事务
session.beginTransaction();
//创建角色1
Role r1=new Role();
r1.setName("Doctor");
session.save(r1);
//创建角色2
Role r2=new Role();
r2.setName("Teacher");
session.save(r2);
//创建角色3
Role r3=new Role();
r3.setName("Farmer");
session.save(r3);
//创建角色4
Role r4=new Role();
r4.setName("Woman");
session.save(r4);
//创建角色5
Role r5=new Role();
r5.setName("Father");
session.save(r5);
//创建用户1。并设置用户角色
User user1=new User();
user1.setName("Anne");
Set roles1=new HashSet();
roles1.add(r1);
roles1.add(r5);
user1.setRoles(roles1);
session.save(user1);
//创建用户2,并设置用户角色
User user2=new User();
user2.setName("Jack");
Set roles2=new HashSet();
roles2.add(r2);
roles2.add(r4);
user2.setRoles(roles2);
session.save(user2);
//创建用户3,并设置用户角色
User user3=new User();
user3.setName("Baby");
Set roles3=new HashSet();
roles3.add(r3);
roles3.add(r2);
user3.setRoles(roles3);
session.save(user3);
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
运行上面的測试方法,将结构写入表:
1.3.2 读取操作
读取操作相对于写入来说就非常easy了。由于是单向的关系,所以在读取时仅仅能通过一端来读取还有一端的内容。也就是说通过User对象来读取Role的内容,例如以下代码:
public void testLoad1(){
Session session=null;
try{
session=HibernateUtils.getSession();
session.beginTransaction();
User user=(User)session.load(User.class, 1);
Set users=user.getRoles();
for(Iterator iter=users.iterator();iter.hasNext();){
Role role=(Role)iter.next();
System.out.println("User.name= "+user.getName()+" and Role.name= "+role.getName());
}
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
运行測试方法。打印生成的内容例如以下:
Hibernate: select user0_.id as id0_0_, user0_.name as name0_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_.name as name2_0_ from t_user_role roles0_ left outer join t_role role1_ on roles0_.role_id=role1_.id where roles0_.user_id=?
User.name= Anne and Role.name= Father
User.name= Anne and Role.name= Doctor
二、双向多对多
双向的多对多映射可以看做是单向的一种扩展。它事实上是为了设置在两端同一时候维护关系,从不论什么一端都可以载入到还有一端的内容。在实现上和单向的起始端是同样的都要使用<many-to-many>标签。
相同以上面的User和Role来做演示样例。上面的演示样例中使用了单向的多对多。不同的是这里要使用双向关系。所以要在Role的一端加入相同的映射关系。并在相应的对象中加入集合映射,当中相应的User内的代码不会发生改变。
2.1 Role.hbm.xml
由于是双向的多对多所以要在对象的两端同一时候加入双向的集合映射,也就是在配置文件里加入<set>标签。并在标签中加入<many-to-many>标签,详细的配置方法类似于上文的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>
<class name="com.src.hibernate.Role" table="t_role">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/> <!-- 加入集合映射,映射的表名应该同User.hbm.xml中配置的表名同样 -->
<set name="users" table="t_user_role">
<key column="role_id"/><!-- 加入映射的外键 -->
<!-- 加入多对多的关系 -->
<many-to-many class="com.src.hibernate.User" column="user_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
2.2 Role.java
同单向的多对多关系中的文件同样,只是须要在对象中加入集合映射Set,使用set来标明映射的集合,例如以下代码:
package com.src.hibernate;
import java.util.Set;
public class Role {
//id标示
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
//名称
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//用户集合
private Set users;
public Set getUsers() {
return users;
}
public void setUsers(Set users) {
this.users = users;
}
}
双向关联映射是在单向的关联映射基础上配置而来的。仅仅须要在映射文件的两端同一时候配置<many-to-many>就可以,也就是说User.hbm.xml和User.java代码和上文中的代码同样,不发生变化,所以不再反复加入了。
结语
完整的单向多对多讨论完整,须要注意的主要是user.hbm.xml中配置的方法,须要使用<many-to-many>标签而且须要生成关系表来维护多对多的关系。其他的内容都是非常easy的。
【Hibernate步步为营】--多对多映射具体解释的更多相关文章
- 【Hibernate步步为营】--继承映射具体解释
上篇文章讨论了多对多映射,在使用多对多映射时重点是使用<many-to-many>标签,并在标签的两端加入外键这样在生成关系时会创建两个关系之间的关系表,通过关系表来维护它们之间的关系,另 ...
- Hibernate的多对一映射
一.创建Java工程,新建Lib文件夹,加入Hibernate和数据库(如MySql.Oracle.SqlServer等)的Jar包,创建 hibernate.cfg.xml 文件,并配置,配置项如下 ...
- Hibernate的多对多映射关系
example: 老师(teacher)和学生(Student)就是一个多对多的关系吧?老师可以有多个学生,学生也可以由多个老师,那在Hibernate中多对多是怎样实现的呢?? 在Hibernate ...
- hibernate单向多对一映射
n21: 1.new 两个实体类,一个代表"多"的一端,一个代表"一"的一端. Customer类: public class Customer { priva ...
- hibernate之多对多映射
目录 第一章 多对多的应用场景 第二章 多对多的映射配置案例 2-1 创建项目和表 2-2 创建持久化类和映射文件 2-3 配置映射文件 2-4 测试 第三章 总结 源码地址:https://gith ...
- hibernate 2 多对多映射
一.实体类 1.Classes.java package cn.gs.wwg.entity; import java.util.Set; public class Classes { private ...
- Hibernate的多对多映射
一.创建Java工程,新建Lib文件夹,加入Hibernate和数据库(如MySql.Oracle.SqlServer等)的Jar包,创建 hibernate.cfg.xml 文件,并配置,配置项如下 ...
- 【Hibernate步步为营】--锁机制具体解释
上篇文章具体讨论了hql的各种查询方法.在讨论过程中写了代码演示样例.hql的查询方法类似于sql,查询的方法比較简单,有sql基础的开发者在使用hql时就会变得相当的简单. Hibernate在操作 ...
- Hibernate(八)多对多映射
一.创建数据表 --学生证表 create table paper ( pid number primary key, pdesc ) , sid number references student( ...
随机推荐
- 条件变量本质-Problem statement-while not( P ) do skip
条件变量相当于订阅-发布机制: 或者相当于同步的通知机制: 订阅和发布具有先后顺序:所以需要互斥量来维护顺序. 顺序不对,存在信号丢失问题. Problem statement[edit] For m ...
- Dapper基础知识四之 利用Dapper获取不同类型的主键值
在下刚毕业工作,之前实习有用到Dapper?这几天新项目想用上Dapper,在下比较菜鸟,这块只是个人对Dapper的一种总结. 一下是Dapper源码几种主键,当主键不包含"ID" ...
- [CTSC2016]单调上升路径
题目:UOJ#201. 题目大意:给定n个点(n是偶数)的完全图,现在要你给每条边确定一个权值(互不相等),使得最长的单调上升路径最短.现在要你输出边的权值. 一条路径被称为单调上升的,如果沿着它走时 ...
- 【Computer Vision】角点检测和匹配——Harris算子
一.基本概念 角点corner:可以将角点看做两个边缘的交叉处,在两个方向上都有较大的变化.具体可由下图中分辨出来: 兴趣点interest point:兴趣点是图像中能够较鲁棒的检测出来的点,它不仅 ...
- python 比较数字大小按从大到小输出
主要用到的python 的知识点 1: 内置函数max 2: 列表的操作 3: while 循环 4 : 错误处理 代码如下: #!/usr/bin/python #coding=u ...
- 2019年北航OO第一单元(表达式求导任务)总结
2019面向对象课设第一单元总结 一.三次作业总结 1. 第一次作业 1.1 需求分析 第一次作业的需求是完成简单多项式导函数的求解,表达式中每一项均为简单的常数乘以幂函数形式,优化目标为最短输出.为 ...
- 在VS2013中配置QT5 win7_64
转自 在VS2013中配置QT5 win7_64 环境: win x64 + vs2013+QT5+vs_addin 下面示例正确配置QT以及VS2013 + QT Addin开发环境: 下载VS20 ...
- 轻松学习JavaScript二十二:DOM编程学习之节点操作
DOM编程不只能够查找三种节点,也能够操作节点.那就是创建,插入,删除.替换和复制节点.先来看节点 操作方法: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQ ...
- 8、java高级面向对象-重载、构造器重载、初始化块、this、super、对象构造和初始化分析、覆盖、toString
1.方法的重载(overload) 同一个类中同时存在一个以上的同名函数,参数个数或类型不同或顺序不同,称为方法的重载. 和返回值无关! 构造器重载:非默认构造器和默认构造器其实就是方法的重载. 2. ...
- Unity3D的场景单位 和 3D建模软件的单位 之间的关系
转载自 : http://www.ceeger.com/Unity/Doc/2011/3D_to_Unity.html Date:2011-08-24 03:52 Unity的系统单位为米,其他3D软 ...