JPA学习 —— 第八课、单向多对一关联关系

多对一关联关系

测试使用两个实体类:
Employee 员工
Department 部门
一个员工可以有多个部门,一个部门只能有一个员工

建立关联关系

使用@ManyToOne注解映射多对一关联关系

Department实体类
由于是单项多对一,所以作为一方不需要主动维护

package com.sssp.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="department")
public class Department {
    @Id
    @Column(name="ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name="DEPT_NAME")
    private String deptName;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getDeptName() {
        return deptName;
    }

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

    @Override
    public String toString() {
        return "Department [id=" + id + ", deptName=" + deptName + "]";
    }
}

Employee 实体类 – 作为多方需要主动维护,需要配置@ManyToOne项

package com.ssj.domain;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name="employee")
public class Employee {

    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Id
    @Column(name="ID")
    private Integer Id;

    @Column(name="EMP_NAME")
    private String empName;

    @Column(name="EMP_BIRTH")
    @Temporal(TemporalType.DATE)
    private Date empBirth;

    @ManyToOne
    @JoinColumn(name="DEPT_ID")
    private Department department;

    public Integer getId() {
        return Id;
    }
    public void setId(Integer id) {
        Id = id;
    }
    public String getEmpName() {
        return empName;
    }
    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public Date getEmpBirth() {
        return empBirth;
    }
    public void setEmpBirth(Date empBirth) {
        this.empBirth = empBirth;
    }
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }
    @Override
    public String toString() {
        return "Employee [Id=" + Id + ", empName=" + empName + ", empBirth="
                + empBirth + ", department=" + department + "]";
    }
}

选择一个空的单元测试运行:
这里写图片描述
department表:
这里写图片描述
employee表:
这里写图片描述
创建了两个表,并且在employee中创建了一个外键DEPT_ID关联到department的主键,就因为在employee中有这几段代码:

@ManyToOne
@JoinColumn(name="DEPT_ID")
private Department department;

说明:
@ManyToOne
标记多对一关系。在多方实体类中声明一方实体,然后标注为@ManyToOne多对一关系。包含西安面几个属性:
optional:是否允许该字段为null,该属性应该根据数据库表的外键约束来确定,默认为true
fetch:表示抓取策略,默认为FetchType.EAGER
cascade:表示默认的级联操作策略,可以指定为ALL,PERSIST,MERGE,REFRESH和REMOVE中的若干组合,默认为无级联操作
targetEntity:表示该属性关联的实体类型.该属性通常不必指定,ORM框架根据属性类型自动判断targetEntity.

@JoinColumn
@JoinColumn和@Column类似,描述的不是一个简单字段,而是一个关联字段。@JoinColumn(name=”DEPT_ID”)在当前表中创建列DEPT_ID关联另一个表的主键(默认关联主键,可以修改,不详讲)。

添加数据:

Department dept1 = new Department();
dept1.setDeptName("第一个部门");

Employee emp1 = new Employee();
emp1.setEmpName("张三");
emp1.setEmpBirth(new Date());
emp1.setDepartment(dept1);
Employee emp2 = new Employee();
emp2.setEmpName("李四");
emp2.setEmpBirth(new Date());
emp2.setDepartment(dept1);

em.persist(dept1);
em.persist(emp1);
em.persist(emp2);

运行以上代码,将会执行三个insert语句,这是毋庸置疑的。

这里写图片描述

但是有两个问题:
1.插入emp1和emp2时,它如何知道dept1的id?我们并没有将插入的dept1查询出来啊。

设了断点后发现,在执行em.persist(dept1); 之后,dept1自动分配了一个ID,相当于从数据库查询出来了。

2.如果先插入emp1和emp2,再插入dept1会怎么样?

按照正常的逻辑,应该会由于插入emp1时找不到外键关联的dept1而报错或者置为空,我们来验证一下。

em.persist(emp1);
em.persist(emp2);
em.persist(dept1);

结果

这里写图片描述

结论:如果先插入emp1,它的DEPT_ID字段会先为空,在插入dept1之后,再进行update操作。因此,在多对一映射关系的情况下,建议先插入“一”的对象(dept),再插入“多”的对象(emp),减少sql语句可以提高效率

关联关系的查询

Employee emp = em.find(Employee.class, 1);

System.out.println(emp.getEmpName());
System.out.println(emp.getDepartment());

这里写图片描述

很简单,建立关联关系后,会自动关联查询。

现在改造一下Employee实体类,在@ManyToOne注解后面加上fetch属性来修改加载策略

//映射多对一的关联关系
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="DEPT_ID")
private Department department;

运行结果:
这里写图片描述

使用懒加载,你会发现JPA先单表查询Employee,然后打印Employee信息。然后要打印Department 时,它才又执行了一次查询语句去查询Department 。也就是,如果你没有使用到Department ,它就不会查询Department

删除

可以删除Employee

Employee emp= em.find(Employee.class, 1);
em.remove(emp);

如果删除Department ,将会因为外键关系而无法删除,除非先把使用这个Department 的Employee 删掉

Department dept= em.find(Department .class, 1);
em.remove(dept);

猜你喜欢

转载自blog.csdn.net/abc997995674/article/details/80229063