Skip to content
On this page

一对多

  • 当对实体类进行一对多设置时,需要在部门实体中新增存放员工的数组、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语句即可完成级联保存操作。
  • 在多对一和一对多关系的实际操作中,建议由多的一方维护关系