Hibernate一对多及多对多操作
一.表与表之间的关系
1.一对多 (老板与雇员)
- 一对多通过外键建立关系
2.多对多 (老师和学生)
- 一个用户里面可以有多个角色,一个角色里面可以有多个用户
- 多对多需要创建第三张表维护关系
二.hibernate 一对多操作
1.一对多映射配置
举例:
- 老板和 雇员 是一对多的关系
(1)创建两个基本的实体类
老板和雇员
//老板
public class Boss {
private int bid;
private String bName;
......
}
//雇员
public class Employee {
private int eid;
private String eName;
......
}
(2)让两个实体之间有相互表示的属性
- 在“多” 的一方 (“雇员类” 中 表示 “老板”)
private Set<Employee> employees = new HashSet<> () ;
//set get
public Set<Employee> getEmployees() {return employees; }
public void setEmployees(Set<Employee> employees) {this.employees = employees; }
- 在“一” 的一方 (“老板类” 中 表示 “雇员”集合)
private Boss boss;
//set get
public Boss getBoss() {return boss; }
public void setBoss(Boss boss) {this.boss = boss; }
(3)配置映射关系
- 一般一个实体类对应一个映射文件
- 在“一” 的一方 老板的配置文件中
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="ph.com.ManyToOne.Boss" table="t_boss">
<id name="bid">
<generator class="native"/>
</id>
<property name="bName"/>
<!-- 在老板映射文件中 表示所有雇员
使用set标签表示所有雇员,set标签里面有name属性
属性值写在老板实体类里面表示雇员的set集合名称
-->
<set name="employees">
<!-- 一对多建表,有外键
hibernate机制,双向维护外键,在一和多的地方都配置外键
column属性值,外键名称
(名称可以随便起,就是 雇员 表中的外键名称,不过要注意和雇员中外键名称保持一致)
-->
<key column="bossid"></key>
<!-- 老板所有的雇员,class里面写雇员实体类全路径 (注意标签顺序) -->
<one-to-many class="ph.com.ManyToOne.Employee"></one-to-many>
</set>
</class>
</hibernate-mapping>
- 在“多” 的一方 雇员的配置文件中
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="ph.com.ManyToOne.Employee" table="t_employee">
<id name="eid">
<generator class="native"/>
</id>
<property name="eName"/>
<!-- 表示雇员所属老板
name属性:因为在雇员实体使用Boss对象表示老板。 (写老板对象名称)
class属性:Boss类全路径
column属性:外键名称
(名称可以随便起,就是 雇员 表中的外键名称,不过要注意和老板中外键名称保持一致)
(注意标签顺序)
-->
<many-to-one name="boss" class="ph.com.ManyToOne.Boss" column="bossid"/>
</class>
</hibernate-mapping>
2.一对多联级保存
(1) 完整写法
Boss boss = new Boss();
Employee employee = new Employee();
boss.setbName("我是boss1");
employee.seteName("我是employee1");
//建立关系
//把雇员对象,放到老板对象的set集合里面
boss.getEmployees().add(employee);
employee.setBoss(boss);
session.saveOrUpdate(boss);
session.saveOrUpdate(employee);
???如果创建好雇员对象,直接添加外键值,何必再动用老板类,为什么这样不行
答:一试便知,因为hibernate中通过对象操作,而对象中没有外键这个属性字段
(2) 简化写法
- 一般根据客户添加联系人
- 第一步 在老板映射文件中进行配置 在set标签中加入 cascade=“save-update”
<set name="employees" cascade="save-update">
- 第二步 创建雇员和老板对象,只需要把雇员放到老板里面就可以了,最终只需要操作添加老板那一步就可以
Employee employee = new Employee();
boss.setbName("我是boss2");
employee.seteName("我是employee2");
//建立关系
//把雇员(employee)对象,放到老板(boss)对象的set集合里面
boss.getEmployees().add(employee);
session.saveOrUpdate(boss);
3.一对多联级删除
(1) 删除某个老板,把客户里面所有的雇员删除
(2)具体实现
- 第一步 在客户映射文件set标签,进行配置
<set name="employees" cascade="save-update,delete">
- 第二步 在代码中直接删除老板(boss)
-
其一 根据id查询对象,调用session里面delete方法删除
Boss boss = session.get(Boss.class,2);
session.delete(boss);
5. 更改主键 (更改雇员的老板)
1.查询新的老板对象
2.查询想要修改的雇员
3.将雇员添加进新的老板对象中
4.将新老板添加进雇员对象中
(和原来的老板没有关系)
Boss boss = session.get(Boss.class,2);
Employee employee = session.get(Employee.class, 1);
boss.getEmployees().add(employee);
employee.setBoss(boss);
//持久态自动提交
5.inverse属性
上述有一些问题,会更新两次主键(因为hibernate双向维护主键的机制)
Hibernate:
update
t_employee
set
eName=?,
bossid=?
where
eid=?
Hibernate:
update
t_employee
set
bossid=?
where
eid=?
在老板(Boss)的一方:(在set标签中,加入inverse属性)
inverse:
true:放弃维护外键
false:维护外键(默认值)
<set name="employees" cascade="save-update,delete" inverse="true">
......
三.hibernate 多对多操作
1.多对多映射配置
(1).第一步 创建实体类 -----老师和学生
(2).第二步 创建映射配置文件
- 老师
<hibernate-mapping>
<class name="ph.com.ManyToMany.Teacher" table="t_teacher">
<id name="tid">
<generator class="native"/>
</id>
<property name="tName"/>
<!--
1. name:老师中学生的set集合
2.第三张关系表的名称
-->
<set name="studentSet" table="t_st">
<!--key标签:
配置当前映射文件在第三张表的外键名称
-->
<key column="t3id"></key>
<!--colum:学生在第三张表中的外键名称
class: 学生的实体类路径
-->
<many-to-many column="s3id" class="ph.com.ManyToMany.Student"></many-to-many>
</set>
</class>
</hibernate-mapping>
- 学生
<hibernate-mapping>
<class name="ph.com.ManyToMany.Student" table="t_student">
<id name="sid">
<generator class="native"/>
</id>
<property name="sName"/>
<set name="teacherSet" table="t_st" >
<key column="s3id"></key>
<many-to-many column="t3id" class="ph.com.ManyToMany.Teacher"></many-to-many>
</set>
</class>
</hibernate-mapping>
2.多对多联级保存(重点)
例如:根据老师保存学生
(1)第一步 在老师映射文件中set标签中添加 cascade值 save-update 进行配置
<set name="studentSet" table="t_st" cascade="save-update">
......
(2)第二步
//建立关系
//将学生放入老师里面
//teacher1----student1/student2
teacher1.getStudentSet().add(student1);
teacher1.getStudentSet().add(student2);
//teacher2----student2/student3
teacher2.getStudentSet().add(student2);
teacher2.getStudentSet().add(student3);
session.save(teacher1);
session.save(teacher2);