1. 一对多
1)设置一对多关系
即不管从多的一方还是一的一方都能找到另一方
1-1 一的一方的pojo:
public class Department {
private Integer id;
private String name;
private Set<Employee> employees = new HashSet<Employee>();
........
}
1-2 多的一方的pojo:
public class Employee {
private Integer id;
private String name;
private Department department;
.....
}
1-3 一的一方的映射文件
<class name="cn.com.cpf.pojo.Department" table="t_department" >
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="employees" table="t_employees">
<key column="departmentId"/>
<one-to-many class="cn.com.cpf.pojo.Employee"/>
</set>
</class>
理解:1>和集合的映射基本相同,只是其中的元素是Class,所以不再使用element,而是使用on-to-many
2>key 还是另一张表的外键
3>因为在一对多映射中,原来的集合表就是现在的多的一方的表(多的一方存储一方的主键,用来关联),所以table就不用指明了,这里是为了便于理解,所以才加上表名
1-4 多的一方的映射文件
<class name="cn.com.cpf.pojo.Employee" table="t_employee">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name" length="20"/>
<many-to-one name="department" class="cn.com.cpf.pojo.Department" column="departmentId"></many-to-one>
</class>
因为要表明是多对一的关系,所以使用many-to-one标签,column用来存储外键,其他的和一般属性完全相同。
1-5 测试
Employee xny = new Employee();
xny.setName("xny");
Employee zq = new Employee();
zq.setName("zq");
Set<Employee> employees = new HashSet<Employee>();
employees.add(zq);
employees.add(xny);
Department department = new Department();
department.setName("cpf");
department.setEmployees(employees);
zq.setDepartment(department);
xny.setDepartment(department);
session.save(zq);
session.save(xny);
session.save(department);
结果为:
Hibernate: insert into t_employee (name, departmentId) values (?, ?)
Hibernate: insert into t_employee (name, departmentId) values (?, ?)
Hibernate: insert into t_department (name) values (?)
Hibernate: update t_employee set name=?, departmentId=? where id=?
Hibernate: update t_employee set name=?, departmentId=? where id=?
Hibernate: update t_employee set departmentId=? where id=?
Hibernate: update t_employee set departmentId=? where id=?
说明:
1> 因为Employee插入在Department之前,这时候Department还没有id(因为此处使用自增长),所以只能先设置null,等Department插入了,有了id,再update,设置外键departmentId,这就有了前两条update。
2> 因为Department一方还没有设置关联,所以就有了后两条update,是Department声明一对多关系
3> 所谓的谁维护关系,就是谁来设置这个外键的值
由上可以推出:
1> 既然先插入Employee要等待Department的id,所以先插入Department再插入Employee可以节省两条update
session.save(department);
session.save(zq);
session.save(xny);
结果为:Hibernate: insert into t_department (name) values (?)
Hibernate: insert into t_employee (name, departmentId) values (?, ?)
Hibernate: insert into t_employee (name, departmentId) values (?, ?)
Hibernate: update t_department set departmentId=? where id=? Hibernate: update t_department set departmentId=? where id=?
2> 既然在employee一端已经在插入的时候设置了外键值,那么没有必要再让department一端再设置了,通过inverse属性可以告诉department不用再设置了 <set name="employees" table="t_employees" inverse="true">
<key column="departmentId"/>
<one-to-many class="cn.com.cpf.pojo.Employee"/>
</set>
session.save(department);
session.save(zq);
session.save(xny);
结果为: Hibernate: insert into t_department (name) values (?)
Hibernate: insert into t_employee (name, departmentId) values (?, ?)
Hibernate: insert into t_employee (name, departmentId) values (?, ?)
2)解除一对多关系
实际上也就是将外键设置为null(因为所谓的对应关系也就是一个外键而已)
1> 从多的一方解除
Employee em = (Employee) session.get(Employee.class, 1);
em.setDepartment(null);
结果: Hibernate: update t_employee set name=?, departmentId=? where id=?
2> 从一的一方解除
前提:必须inverse属性设置为false,不然他都不管理了怎么可能解除关系?
Department department = (Department) session.get(Department.class, 2);
Employee o = (Employee) session.get(Employee.class, 3);
department.getEmployees().remove(o);
3) 删除关联对象
1> 删除多的一方
Employee em = (Employee) session.get(Employee.class, 1);
session.delete(em);
结果:直接删,对一的一方完全无影响(因为外键就保存在自己这里,删了也就连关系一起删了,肯定无影响) 2> 删除一的一方
a.和多的对象没有关联——直接删,当然无影响
b.和多的对象有关联,inverse属性为true
inverse为true,不能管理外键,所以删除就会报异常
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails
c.和多的对象有关联,inverse属性为false 可以删,因为自己可以管理外键
结果:
Hibernate: update t_employee set departmentId=null where departmentId=?
Hibernate: delete from t_department where id=?
可以看到先设置外键为null,再删除