一對多關係介紹
在一對多關係中,我們習慣把一的一方稱之爲主表,把多的一方稱之爲從表。在數據庫中建立一對多的關係,需要使用數據庫的外鍵約束。
什麼是外鍵?指的是從表中有一列,取值參照主表的主鍵,這一列就是外鍵。
一對多數據庫關係的建立,如下圖所示:
實體關係建立及映射配置
公司實體(一的一方):
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("[email protected]");
e1.setPhone("10086");
e1.setCompany(company);
Employee e2 = new Employee();
e2.setName("員工4");
e2.setEmail("[email protected]");
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 (?, ?, ?, ?, ?)