我们以部门和员工的关系为例讲解一对多关联关系映射时,删除部门时,如果部门有关联的员工且inverse属性为false,那么由于可以维护关联关系,它就会先把关联的员工的外键列设为null值,再删除自己。但是此刻希望删除部门时,就附带着把该部门下的所有员工都删掉,这时就需要引入cascade属性了。
当Hibernate持久化一个临时对象时,在默认情况下,它不会自动持久化所关联的其他临时对象,而是会抛出TransientObjectException。如果设定many-to-one元素的cascade属性为save-update的话,可实现自动持久化所关联的对象。如:
to-one name="customer"
column="CUSTOMER_ID"
class="..Customer"
cascade="save-update"
not-null="true" />
级联指的是当主控方执行操作时,关联对象(被动方)是否同步执行同一操作。
每个Hibernate session的基本操作包括persist()、merge()、saveOrUpdate()、delete()、lock()、refresh()、evict()、replicate(),这些操作都有对应的级联风格(cascade style)。这些级联风格(cascade style)风格分别命名为persist、merge、save-update、delete、lock、refresh、evict、replicate。
级联风格 | Session中的方法 |
---|---|
persist | persist() |
merge | merge() |
save-update | save()、update()、saveOrUpdate() |
delete | delete() |
lock | lock() |
refresh | refresh() |
evict | evict() |
replicate | replicate() |
如果你希望一个操作被顺着关联关系级联传播,你必须在映射文件中指出这一点。
指定级联风格:
<one-to-one name="person" cascade="persist" />
级联风格(cascade style)是可组合的:
<one-to-one name="person" cascade="persist,delete" />
你可以使用cascade=”all”来指定全部操作都顺着关联关系级联(cascaded)。默认值是cascade=”none”,即任何操作都不会被级联(cascaded)。
在对象/关系映射文件中,用于映射持久化类之间关联关系的元素,如
、
和
都有一个cascade属性。
还是回到开头我们提出的需求,即删除部门时,就附带着把该部门下的所有员工都删掉。要满足这个需求,我们最好新建一个普通java工程,如Hibernate_Test,然后在cn.itcast.f_hbm_oneToManyb包下新建持久化类——Department.java和Employee.java。
持久化类——Department.java的代码如下:
/**
* 部门
* @author li ayun
*
*/
public class Department {
private Integer id;
private String name;
private Set employees = new HashSet(); // 关联的很多个员工
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set getEmployees() {
return employees;
}
public void setEmployees(Set employees) {
this.employees = employees;
}
@Override
public String toString() {
return "[Department: id=" + id + ", name=" + name + "]";
}
}
持久化类——Employee.java的代码如下:
/**
* 员工
* @author li ayun
*
*/
public class Employee {
private Integer id;
private String name;
private Department department; // 关联的部门对象
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
@Override
public String toString() {
return "[Employee: id=" + id + ", name=" + name + "]";
}
}
由于我们先前就分析过各个持久化类在数据库中所对应的表的结构,所以我们很容易就写出各个持久化类相应的映射配置文件了。
先在cn.itcast.f_hbm_oneToMany包中创建Department类对应的映射配置文件——Department.hbm.xml。
<hibernate-mapping package="cn.itcast.f_hbm_oneToMany">
<class name="Department" table="department">
<id name="id">
<generator class="native">generator>
id>
<property name="name" />
<set name="employees" cascade="save-update,delete">
<key column="departmentId">key>
<one-to-many class="Employee"/>
set>
class>
hibernate-mapping>
在
元素中设置cascade=”save-update,delete”,即表示只须保存/修改某部门,该部门下的所有员工都将保存/修改,或者删除部门时,就附带着把该部门下的所有员工都删掉。
然后也是在该包中创建Employee类对应的映射配置文件——Employee.hbm.xml。
<hibernate-mapping package="cn.itcast.f_hbm_oneToMany">
<class name="Employee" table="employee">
<id name="id">
<generator class="native">generator>
id>
<property name="name" type="string" column="name" />
<many-to-one name="department" class="Department" column="departmentId">many-to-one>
class>
hibernate-mapping>
接下来,我们从以下2个方面来编写代码进行测试:
所以,我们要在cn.itcast.f_hbm_oneToMany包中编写一个单元测试类——Application.java。
public class Application {
private static SessionFactory sessionFactory = new Configuration() //
.configure() //
.addClass(Department.class) // 添加Hibernate实体类(加载对应的映射文件)
.addClass(Employee.class) // 添加Hibernate实体类(加载对应的映射文件)
.buildSessionFactory();
// 保存,有关联关系
@Test
public void testSave() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
// 新建对象
Department department = new Department();
department.setName("开发部");
Employee employee1 = new Employee();
employee1.setName("张三");
Employee employee2 = new Employee();
employee2.setName("李四");
// 关联起来
employee1.setDepartment(department); // 告诉员工他属于哪个部门
employee2.setDepartment(department);
department.getEmployees().add(employee1); // 告诉部门它有两个关联的员工
department.getEmployees().add(employee2);
// 保存
session.save(department); // 保存部门
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
// 删除对象,对关联对象的影响
@Test
public void testDelete() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
// 删除部门方(一方)
Department department = (Department) session.get(Department.class, 1);
session.delete(department);
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
}
这样,当保存部门时,会级联保存该部门下的所有员工,或者删除部门时,就会级联删除该部门下的所有员工。我们也可以配置员工级联删除部门,但这样做,在业务上是极不合理的。
一般是多对一和多对多的时候不使用级联,一对一和一对多可以使用级联,这两种情况使用级联比较多,总结来说,这个对象归你控制,你就能够级联,它不归你一个人所有,那你就不要级联。
还有一点要注意,inverse属性和cascade属性毛关系都没有。