Appearance
一对多
- 当对实体类进行一对多设置时,需要在部门实体中新增存放员工的数组、Set、List类型的对象
- 在Dept类中添加关联Employee集合对象employees,并使用@OneToMany注解标注一对多关联
Dept类
java
package com.huangjiliang.jpa.entity;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "dept")
@Data
@Accessors(chain = true)
public class Dept {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column
private String deptName;
@Column
private String deptCode;
@OneToMany
@JoinColumn(name = "dept_id", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT))
private List<Employee> employees;
}
关联查询测试
java
/**
* 一对多关联查询
*/
@Test
public void oneToManyCascadeFindAll() {
Dept dept = deptRepository.findById(1).get();
logger.info(dept.getDeptName());
for (Employee employee : dept.getEmployees()) {
logger.info(employee.getName());
}
}
- 运行oneToManyCascadeFindAll()测试方法之后,观察控制台会发现先打印了查询部门表并输出了部门信息,然后根据部门ID再去查询员工表,并打印处对应的员工信息,这说明一对多默认使用了懒加载机制
- 如果将该方法设置成及时加载模式,则不论是否查询对应的元u南宫,均会将员工数据一并查出,但因为一对多级联查询会影响性能,故在一般项目中不建议及时查询使用
级联保存测试(方式1)
Dept修改级联保存设置
java
@OneToMany(cascade = CascadeType.PERSIST)
@JoinColumn(name = "dept_id", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT))
private List<Employee> employees;
java
/**
* 一对多级联保存
*/
@Test
public void oneToManyCascadeInsert() {
Dept dept = new Dept();
dept.setDeptName("东部战区").setDeptCode("100000");
Employee e1 = new Employee();
e1.setName("1111");
Employee e2 = new Employee();
e2.setName("2222");
List<Employee> list = new ArrayList<>();
list.add(e1);
list.add(e2);
dept.setEmployees(list);
deptRepository.save(dept);
}
执行oneToManyCascadeInsert以上测试方法查看控制台,打印如下信息
Hibernate:
insert
into
dept
(dept_code, dept_name)
values
(?, ?)
Hibernate:
insert
into
employee
(age, dept_id, gender, name, user_number)
values
(?, ?, ?, ?, ?)
Hibernate:
insert
into
employee
(age, dept_id, gender, name, user_number)
values
(?, ?, ?, ?, ?)
Hibernate:
update
employee
set
dept_id=?
where
id=?
Hibernate:
update
employee
set
dept_id=?
where
id=?
- 先指定一条插入部门的语句,然后指定一条插入员工的语句,最后通过更新员工表的dept_id值更新,这是因为dept对象中employees,而employee对象中没有设置相关的dept信息,所以在插入员工时,并不能将dept_id值插入,只能暂时保存为null,注意此时如果表employee表将dept_id设置为not null,则会报异常,在通过dept去更新employee表来进行dept_id设置
- 以上方式维护关系多执行了两条update语句,影响了性能。而通过OneToMany上使用mappedby属性可以解决这一问题。mappedby实际上就是Hibernate的inverse属性,作用就是将关联关系的维护交给对方,需要注意的是,如果加mappedby属性,则需要将@joineColumn注解去掉
级联保存测试(方式2)
Dept修改关联属性。使用mappedby属性将维护交给对方
java
@OneToMany(cascade = CascadeType.PERSIST, mappedBy = "dept")
// @JoinColumn(name = "dept_id", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT))
private List<Employee> employees;
java
/**
* 一对多级联保存
*/
@Test
public void oneToManyCascadeInsert2() {
Dept dept = new Dept();
dept.setDeptName("西部战区").setDeptCode("200000");
Employee e1 = new Employee();
e1.setName("3333");
Employee e2 = new Employee();
e2.setName("4444");
List<Employee> list = new ArrayList<>();
list.add(e1);
list.add(e2);
dept.setEmployees(list);
e1.setDept(dept);
e2.setDept(dept);
deptRepository.save(dept);
}
- 测试需要特别注意的是,此时是用多的一方来维护关系,以上改代码中必须有
e1.setDept(dept);e2.setDept(dept);
才可以保存员工表中dept_id的字段。此时,因为多方拥有了一方的值所以在设置employee时可以直接加入dept_id,这是只需要执行三条insert语句即可完成级联保存操作。 - 在多对一和一对多关系的实际操作中,建议由多的一方维护关系