直接上例子:
部门和员工的关系:
一个部门可以有多个员。一个员工只属于一个部门。
目录结构:
Employee.java
public class Employee {
private Integer id;
private String name;
private Department department; // 关联的部门对象
Department.java
public class Department {
private Integer id;
private String name;
private Set<Employee> employees = new HashSet<Employee>(); // 关联多个员工
部门和员工的映射文件。
Department.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.zll.test">
<class name="Department" table="department">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name"/>
<!-- employees属性,Set集合,表达的是本类与Employee的一对多
class属性:关联的实体类型
key子元素:对方表中的外键列(多方的那个表)
inverse属性:(对查询获取数据没有影响)
默认为false,表示本方维护关联关系。
如果为true,表示本方不维护关联关系。
只是影响数据的插入和删除时,否能可以以联动修改外键列的值(设成有效值或是null值)。
cascade属性:
默认为none,代表不级联。
级联是指操作主对象时,对关联的对象也做相同的操作。
可设为:delete, save-update, all, none ...
-->
<set name="employees" cascade="all" inverse="true">
<key column="departmentId"></key>
<one-to-many class="Employee"/>
</set>
</class>
</hibernate-mapping>
Employee.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.zll.test">
<class name="Employee" table="employee">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name" type="string" column="name"/>
<!-- department属性,表达的是本类与Department的多对一
class属性:关联的实体类型
column属性:外键列(引用关联对象的表的主键)
外键方式必须维护关联关系的, 所有没有 inverse参数
-->
<many-to-one name="department" class="Department" column="departmentId" ></many-to-one>
</class>
</hibernate-mapping>
测试:
package com.zll.test;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class App {
private static SessionFactory sessionFactory = new Configuration()//
.configure()//
.addClass(Department.class)// 添加Hibernate实体类(加载对应的映射文件)
.addClass(Employee.class)// 添加Hibernate实体类(加载对应的映射文件)
.buildSessionFactory();
// 保存,有关联关系
@Test
public void testSave() throws Exception {
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);
// 保存要注意顺序。
// 由于员工持有关联关系,所以最好在员工插入前,先插入部门,否者会多执行两条 update 语句赵成资源的浪费。
session.save(department);
session.save(employee1);
session.save(employee2);
/* 不推荐的方式: 会多出两条 update语句
//第二种保存方式 部门关联员工。(前提是 inverse=false 默认为false )
//inverse 为false 表示主动维护关联关系
department.getEmployees().add(employee1);
department.getEmployees().add(employee2);
// 由于部门主动维护关联关系,在插入数据过程如下:
//1、部门首先会将自己持有的员工插入到数据库 2、在将自己查到到数据库 3 、在更新关联关系
//这样也会多出两条 update语句,不推荐使用。
session.save(department);
*/
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
// 获取,可以获取到关联的对方
@Test
public void testGet() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
// 获取一方,并显示另一方信息
Department department = (Department) session.get(Department.class, 40);
System.out.println(department);
System.out.println(department.getEmployees());
System.out.println("================================");
Employee employee = (Employee) session.get(Employee.class, 87);
System.out.println(employee);
System.out.println(employee.getDepartment());
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
// 解除关联关系
@Test
public void testRemoveRelation() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
// // 从员工方解除
// Employee employee = (Employee) session.get(Employee.class, 1);
// employee.setDepartment(null);
// 从部门方解除(与inverse有关系,为false时可以解除)
Department department = (Department) session.get(Department.class, 3);
department.getEmployees().clear();
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
// 删除对象,对关联对象的影响
@Test
public void testDelete() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
// // 删除员工方(多方),对对方没有影响
// Employee employee = (Employee) session.get(Employee.class,2);
// session.delete(employee);
// 删除部门方(一方)
// a, 如果没有关联的员工:能删除。
// b, 如果有关联的员工且inverse=true,由于不能维护关联关系,直接执行删除,就会有异常
// c, 如果有关联的员工且inverse=false,由于可以维护关联关系,他就会先把关联的员工的外键列设为null值,再删除自己。
Department department = (Department) session.get(Department.class, 4);
session.delete(department);
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
}
cascade属性:级联操作。
默认为none,代表不级联。
级联是指操作主对象时,对关联的对象也做相同的操作。
可设为:delete, save-update, all, none …
举例:如果部门 cascade=delete 那么在删除部门时,会同时删除 所在部门的所有员工。