Jpa之OneToMany
一对多关系介绍
在一对多关系中,我们习惯把一的一方称之为主表,把多的一方称之为从表。在数据库中建立一对多的关系,需要使用数据库的外键约束。
什么是外键?指的是从表中有一列,取值参照主表的主键,这一列就是外键。
一对多数据库关系的建立,如下图所示:
实体关系建立及映射配置
公司实体(一的一方):
package com.example.jpademo.ono2many.entity;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.Set;
@Setter
@Getter
//@Data 会引发堆栈溢出,不推荐使用
@Entity
@Table(name = "company")
public class Company {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String name;
private String address;
private String industry;
// @OneToMany(targetEntity = Employee.class)
// @JoinColumn(name = "company_id",referencedColumnName = "id" )
@OneToMany(mappedBy = "company",fetch = FetchType.EAGER)
private Set<Employee> employees;
@Override
public String toString() {
return "Company{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
", industry='" + industry + '\'' +
'}';
}
}
员工实体(多的一方):
package com.example.jpademo.ono2many.entity;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
@Setter
@Getter
@Entity
@Table(name = "employee")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String name;
private String phone;
private String email;
@ManyToOne(targetEntity = Company.class)
@JoinColumn(name = "company_id",referencedColumnName = "id")
private Company company;
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", phone='" + phone + '\'' +
", email='" + email + '\'' +
'}';
}
}
注解说明
@OneToMany
作用:建立一对多的关系映射
属性:
targetEntityClass
:指定多的一方的类的字节码(XXX.class
);如果从表集合类中指定了具体类型了,不需要使用targetEntity;mappedBy
:指定从表实体类中引用主表对象的名称。mappedBy标签一定是定义在被拥有方的,他指向拥有方;mappedBy
的含义,应该理解为,拥有方能够自动维护跟被拥有方的关系,当然,如果从被拥有方,通过手工强行来维护拥有方的关系也是可以做到的;cascade
:指定要使用的级联操作;fetch
:指定是否采用延迟加载,参数值为FetchType.LAZY
和FetchType.MERGE
。默认为FetchType.LAZY
,表示懒加载。因为关联的多个对象通常不必从数据库预先读取到内;orphanRemoval
:是否使用孤儿删除,比如在一对多的关系中,Student包含多个book,当在对象关系中删除一个book时,此book即成为孤儿节点。
@ManyToOne
作用:建立多对一的关系
属性:
targetEntityClass
:指定一的一方实体类字节码,如果主表实体类中指定了具体类型了,不需要使用targetEntity;- cascade:指定要使用的级联操作;
- fetch:指定是否采用延迟加载;
- optional:关联是否可选。默认为true。如果设置为false,则必须始终存在非空关系。
@JoinColumn
作用:用于定义主键字段和外键字段的对应关系。
属性:
- name:指定外键字段名
- referencedColumnName:指定引用主表的主键字段名称
- unique:是否唯一。默认值不唯一
- nullable:是否允许为空。默认值允许。
- insertable:是否允许插入。默认值允许。
- updatable:是否允许更新。默认值允许。
- columnDefinition:列的定义信息。
一对多的操作
保存操作
@Test
// @Transactional //开启事务
// @Rollback(false)//设置为不回滚
public void testAdd2(){
//先保存一,再保存多
Company company = new Company();
company.setName("公司2");
company.setIndustry("电子");
company.setAddress("通讯地址02");
Employee e1 = new Employee();
e1.setName("员工3");
e1.setEmail("123456@qq.com");
e1.setPhone("10086");
e1.setCompany(company);
Employee e2 = new Employee();
e2.setName("员工4");
e2.setEmail("123456@qq.com");
e2.setPhone("10086");
e2.setCompany(company);
// Set<Employee> employees = new HashSet<>();
// employees.add(e1);
// employees.add(e2);
// company.setEmployees(employees);
companyRepository.save(company);
employeeRepository.save(e1);
employeeRepository.save(e2);
}
执行SQL:
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into company (address, industry, name, id) values (?, ?, ?, ?)
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into employee (company_id, email, name, phone, id) values (?, ?, ?, ?, ?)
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into employee (company_id, email, name, phone, id) values (?, ?, ?, ?, ?)