2.1 Liên kết ở mức bảng

Chúng ta đã thấy cách Hibernate lưu trữ các bộ sưu tập trong các bảng phụ trợ. Bây giờ, hãy tìm hiểu cách tổ chức các mối quan hệ giữa các bảng chính thức lưu trữ các lớp Thực thể thực.

Có bốn loại mối quan hệ giữa các lớp Thực thể trong Hibernate:

  • một đối một
  • một đến nhiều
  • nhiều -to- một
  • nhiều -to- nhiều

Và chúng tôi sẽ bắt đầu phân tích với tùy chọn đơn giản nhất - nhiều - một .

Bạn đã bắt gặp mối quan hệ như vậy giữa các bảng trong SQL. Đây là những gì nó thường trông giống như:

nhận dạng tên nghề nghiệp lương tuổi ngày tham gia
1 Ivanov Ivan lập trình viên 100000 25 30-06-2012
2 Petrov Petr lập trình viên 80000 23 2013-08-12
3 Ivanov Serge Kiểm thử 40000 ba mươi 2014-01-01
4 Rabinovich Moisha Giám đốc 200000 35 2015-05-12
5 kirienko anastasia Quản lý văn phòng 40000 25 2015-10-10
6 Vaska Con mèo 1000 3 2018-11-11

bảng nhân viên:

Bảng này có các cột sau:

  • id INT
  • tên VARCHAR
  • nghề nghiệp VARCHAR
  • tiền lương
  • tuổi INT
  • join_date NGÀY

Và đây là cách bảng nhiệm vụ , chứa các nhiệm vụ cho nhân viên, trông như thế nào:

nhận dạng Mã hiệu công nhân tên thời hạn
1 1 Sửa lỗi ở frontend 2022-06-01
2 2 Sửa lỗi trên backend 2022-06-15
3 5 Mua cà phê 2022-07-01
4 5 Mua cà phê 2022-08-01
5 5 Mua cà phê 2022-09-01
6 (VÔ GIÁ TRỊ) Dọn dẹp văn phòng (VÔ GIÁ TRỊ)
7 4 Tận hưởng cuộc sống (VÔ GIÁ TRỊ)
số 8 6 Tận hưởng cuộc sống (VÔ GIÁ TRỊ)

Bảng này chỉ có 4 cột:

  • id – số nhiệm vụ duy nhất (và các hàng trong bảng);
  • employee_id – ID nhân viên từ bảng nhân viên được giao nhiệm vụ;
  • tên – tên và mô tả của nhiệm vụ;
  • thời hạn - thời gian mà nhiệm vụ phải được hoàn thành.

Chúng tôi thấy rằng nhiều hàng trong bảng nhiệm vụ có thể tham chiếu đến một mục duy nhất trong bảng nhân viên. Mối quan hệ cấp độ bảng như vậy được gọi là nhiều- một.

2.2 Mối quan hệ với mức lớp Java

Ngoài giao tiếp ở cấp độ bảng, bạn cũng có thể tổ chức giao tiếp ở cấp độ của các lớp Thực thể trong Hibernate. Điều này được thực hiện với một chú thích @ManyToOne.

Nhưng trước tiên, hãy tạo hai lớp: 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;
}

Và một lớp thứ hai để lưu trữ công việc của nhân viên:


@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;
}

Tất cả đều ổn với các lớp này, nhưng không có mối quan hệ nào giữa chúng phản ánh thực tế là trường employeeId của lớp EmployeeTask đề cập đến trường id của lớp Employee. Đã đến lúc phải sửa nó

2.3 Chú thích @ManyToOne.

Đầu tiên, trong Java, chúng ta đã quen với việc thao tác trên các đối tượng (và các tham chiếu đối tượng) hơn là id của chúng. Vì vậy, trước hết, thay vì trường employeeId trong lớp EmployeeTask, chúng ta hãy trỏ đến một đối tượng có kiểu là Employee. Đây là lớp mới của chúng ta sẽ như thế nào:


@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;
}

Với sự trợ giúp của chú thích @ManyToOne , chúng tôi đã chỉ ra rằng nhiều đối tượng EmployeeTask có thể tham chiếu đến một đối tượng thuộc loại Employee. Ngoài ra, bằng cách sử dụng chú thích @JoinColumn , chúng tôi đã chỉ ra cột nào trong bảng của chúng tôi id của đối tượng Nhân viên được lưu trữ.

2.4 Ví dụ về yêu cầu

Và bây giờ hãy trình bày một số ví dụ về cách Hibernate có thể làm việc với các lớp liên quan như vậy.

kịch bản một

Hãy viết một truy vấn để tìm ra tất cả các tác vụ đã được gán cho một người dùng cụ thể. Đây là cách truy vấn này trông như thế nào trong HQL:

from EmployeeTask where employee.name = "Ivan Ivanovich"

Bạn chỉ có thể tham chiếu đến các trường của các lớp phụ thuộc thông qua một dấu chấm. Nó rất thoải mái. Nhưng hãy viết truy vấn này dưới dạng mã 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();

kịch bản hai

Hãy viết truy vấn trả về danh sách nhân viên có nhiệm vụ quá hạn. Một nhiệm vụ quá hạn nếu thời hạn của nó là trong quá khứ. Đây là giao diện của truy vấn đó trong SQL:


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

DISTINCTđược sử dụng vì có thể có nhiều nhiệm vụ được giao cho một người dùng.

Và bây giờ hãy viết truy vấn tương tự trong HQL:

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

Nhân viên trong truy vấn này là một trường của lớp EmployeeTask

tình huống ba

Giao tất cả các nhiệm vụ chưa được giao cho giám đốc. Truy vấn SQL sẽ trông như thế này:


UPDATE task SET employee_id = 4 WHERE employee_id IS NULL

Và bây giờ hãy viết truy vấn tương tự trong HQL:

update EmployeeTask set employee = :user where employee is null

Truy vấn cuối cùng là truy vấn khó nhất. Chúng ta cần chuyển ID của giám đốc, nhưng lớp EmployeeTask không chứa trường để chúng ta có thể viết id, thay vào đó nó chứa trường Nhân viên nơi chúng ta cần gán tham chiếu đến một đối tượng thuộc loại Nhân viên.


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();