多对一关联关系
测试使用两个实体类:
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);