2.1 表級鏈接

我們已經看到 Hibernate 如何在輔助表中存儲集合。現在讓我們弄清楚如何組織存儲真實實體類的完整表之間的關係。

Hibernate中實體類之間的關係有四種:

  • 一對一_ _
  • 一對多_ _
  • 多對一_ _
  • 多對多_ _

我們將從最簡單的選項開始分析——多對一

您已經遇到過 SQL 中表之間的這種關係。它通常是這樣的:

ID 姓名 職業 薪水 年齡 加入日期
1個 伊万諾夫伊万 程序員 100000 25 2012-06-30
2個 彼得羅夫彼得 程序員 80000 23 2013-08-12
3個 伊万諾夫謝爾蓋 測試儀 40000 三十 2014-01-01
4個 拉比諾維奇·莫伊沙 導演 200000 35 2015-05-12
5個 基連科阿納斯塔西婭 辦公室主管 40000 25 2015-10-10
6個 瓦斯卡 1000 3個 2018-11-11

員工表:

該表包含以下列:

  • 標識符整數
  • 名稱VARCHAR
  • 職業VARCHAR
  • 薪水整數
  • 年齡整數
  • join_date日期

這就是包含員工任務的任務表的樣子:

ID 員工ID 姓名 最後期限
1個 1個 修復一個前端bug 2022-06-01
2個 2個 修復後端的一個bug 2022-06-15
3個 5個 買咖啡 2022-07-01
4個 5個 買咖啡 2022-08-01
5個 5個 買咖啡 2022-09-01
6個 (無效的) 打掃辦公室 (無效的)
7 4個 享受生活 (無效的)
8個 6個 享受生活 (無效的)

該表只有 4 列:

  • id – 唯一的任務編號(和表中的行);
  • employee_id – 分配任務的員工表中的員工 ID;
  • 名稱——任務的名稱和描述;
  • deadline - 任務必須完成的時間。

我們看到任務表中的許多行可以引用員工表中的單個條目。這種表級關係稱為多對一

2.2 與Java類級別的關係

除了表級別的通信,您還可以在 Hibernate 中的實體類級別組織通信。這是通過註釋完成的@ManyToOne

但首先,讓我們創建兩個類:EmployeeEmployeeTask


@Entity
@Table(name="employee")
class Employee {
   @Column(name="id")
   public Integer id;
 
   @Column(name="name")
   public String name;
 
   @Column(name="occupation")
   public String occupation;
 
   @Column(name="salary")
   public Integer salary;
 
   @Column(name="join_date")
   public Date join;
}

第二類存儲員工工作:


@Entity
@Table(name="task")
class EmployeeTask {
   @Column(name="id")
   public Integer id;
 
   @Column(name="name")
   public String description;
 
  @Column(name="employee_id")
   public Integer employeeId;
 
   @Column(name="deadline")
   public Date deadline;
}

這些類都很好,但是它們之間沒有關係可以反映 EmployeeTask 類的 employeeId 字段引用 Employee 類的 id 字段這一事實。是時候修復它了

2.3 @ManyToOne註解。

首先,在 Java 中我們習慣於操作對象(和對象引用)而不是它們的 id。所以首先,讓我們指向一個 Employee 類型的對象,而不是 EmployeeTask 類中的 employeeId 字段。這是我們的新課程的樣子:


@Entity
@Table(name="task")
class EmployeeTask {
   @Column(name="id")
   public Integer id;
 
   @Column(name="name")
   public String description;
 
   @ManyToOne
   @JoinColumn(name = "employee_id")
   public Employee employee;
 
   @Column(name="deadline")
   public Date deadline;
}

在註釋 的幫助下@ManyToOne,我們已經指出許多 EmployeeTask 對象可以引用一個 Employee 類型的對象。此外,使用註釋 @JoinColumn,我們指出了 Employee 對象的 ID 存儲在表的哪一列中。

2.4 請求示例

現在讓我們展示一些 Hibernate 如何與這些相關類一起工作的例子。

場景一

讓我們編寫一個查詢來找出已分配給特定用戶的所有任務。下面是這個查詢在 HQL 中的樣子:

from EmployeeTask where employee.name = "Ivan Ivanovich"

您可以簡單地通過一個點來引用依賴類的字段。很舒服。但是讓我們仍然以 Java 代碼的形式編寫這個查詢:


String hql = "from EmployeeTask where employee.name = :username";
Query<EmployeeTask> query = session.createQuery( hql, EmployeeTask.class);
query.setParameter("username", "Ivan Ivanovich");
List<EmployeeTask> resultLIst = query.list();

情景二

讓我們編寫一個查詢,返回一個有逾期任務的員工列表。如果截止日期已過,則任務已過期。下面是該查詢在 SQL 中的樣子:


SELECT DISTINCT employee.*
FROM task JOIN employee ON task.employee_id = employee.id
WHERE task.deadline < CURDATE();

DISTINCT之所以使用,是因為可以將許多任務分配給一個用戶。

現在讓我們用 HQL 編寫相同的查詢:

select distinct employee from EmployeeTask where deadline < CURDATE();

此查詢中的 Employee 是 EmployeeTask 類的一個字段

情況三

將所有未分配的任務分配給主管。SQL 查詢將如下所示:


UPDATE task SET employee_id = 4 WHERE employee_id IS NULL

現在讓我們用 HQL 編寫相同的查詢:

update EmployeeTask set employee = :user where employee is null

最後一個查詢是最難的。我們需要傳遞主管的 ID,但是 EmployeeTask 類不包含我們可以寫入 id 的字段,而是包含一個 Employee 字段,我們需要在其中分配對 Employee 類型對象的引用。


Employee director = session.get(Employee.class, 4);
 
String hql = "update EmployeeTask set employee = :user where employee is null";
Query<EmployeeTask> query = session.createQuery(hql, EmployeeTask.class);
query.setParameter("user", director);
query.executeUpdate();