3.1 การแมปเอนทิตีที่ขึ้นต่อกัน

ใน SQL คุณสามารถเขียนแบบสอบถามโดยใช้ JOIN เป็นไปได้ไหมที่จะทำเช่นเดียวกันใน HQL? คำตอบสั้น ๆ คือใช่ แต่คำตอบแบบเต็มจะน่าสนใจยิ่งขึ้น

อันดับแรก เมื่อเราเขียน JOIN ใน SQL มักจะหมายความว่าตารางหนึ่งอ้างอิงถึงอีกตารางหนึ่ง ตัวอย่างเช่น ตารางงานมีคอลัมน์ customer_id ที่อ้างถึงคอลัมน์ id ของตารางพนักงาน

การพึ่งพานี้สามารถอธิบายได้โดยใช้คำอธิบายประกอบใน Hibernate ขั้นแรก ให้สร้างเอนทิตีสำหรับตารางของเรา ก่อนอื่นมาอธิบายตารางพนักงาน:

@Entity
@Table(name="employee")
class Employee {
   @Column(name="id")
   public Integer id;

   @Column(name="name")
   public String name;

   @Column(name="salary")
   public Integer salary;

   @Column(name="join_date")
   public Date joinDate;
}

และ คลาส EmployeeTaskสำหรับ ตาราง งาน :

@Entity
@Table(name="task")
class EmployeeTask {
   @Column(name="id")
   public Integer id;

   @Column(name="name")
   public String name;

   @Column(name="employee_id")
   public Integer employeeId;

   @Column(name="deadline")
   public Date deadline;
}

ทุกอย่างดี แต่มีข้อเสนอแนะอย่างหนึ่ง ลองดูที่ ช่อง รหัสพนักงานในตัวอย่างสุดท้าย:

@Column(name="employee_id")
public Integer employeeId;

คุณสังเกตเห็นอะไรแปลก ๆ หรือไม่? ถ้าไม่ ก็แสดงว่าคุณได้สร้างวิธีคิดในภาษา SQL แล้ว

สิ่งหนึ่งคือในภาษา Java เรามักจะอธิบายการพึ่งพาดังกล่าวแตกต่างกันเล็กน้อย:

public Employee employee;

เราไม่จำเป็นต้องระบุid เรามักจะระบุตัวแปรที่เก็บการอ้างอิงถึง วัตถุ Employee หรือเก็บค่าว่างหากไม่มีวัตถุดังกล่าว

และไฮเบอร์เนตช่วยให้เราสามารถอธิบายสถานการณ์ดังกล่าวโดยใช้คำอธิบายประกอบ:

@ManyToOne
@JoinColumn(name="employee_id", nullable=true)
public Employee employee;

คำอธิบายประกอบ@ManyToOneจะบอก Hibernate ว่า เอนทิ ตี EmployeeTask จำนวนมาก สามารถอ้างถึง เอน ทิ ตี Employee เดียว

และคำอธิบายประกอบจะ@JoinColumnระบุชื่อของคอลัมน์ที่ จะใช้ id ข้อมูลที่จำเป็นอื่น ๆ ทั้งหมดจะนำมาจากคำอธิบายประกอบของคลาสพนักงาน

ผลลัพธ์สุดท้ายจะมีลักษณะดังนี้:

@Entity
@Table(name="task")
class EmployeeTask
{
   @Column(name="id")
   public Integer id;

   @Column(name="name")
   public String name;

   @ManyToOne
   @JoinColumn(name="employee_id", nullable=true)
   public Employee employee;

   @Column(name="deadline")
   public Date deadline;
}

3.2 การใช้การรวมใน HQL

และตอนนี้ มาดูวิธีการเขียนแบบสอบถามไปยังเอนทิตีที่เกี่ยวข้องใน HQL

สถานการณ์แรก

เรามีพนักงาน (Employee) และเราต้องการรับรายการงานของเขา ต่อไปนี้คือลักษณะของแบบสอบถามใน SQL:

SELECT task.* FROM task JOIN employee ON task.employee_id = employee.id
WHERE employee.name = "Ivan Ivanovich";

และตอนนี้มาเขียนแบบสอบถามเดียวกันใน HQL:

from EmployeeTask where employee.name = "Ivan Ivanovich"

คลาสEmployeeTaskมี ฟิลด์ พนักงานและมี ฟิลด์ ชื่อดังนั้นแบบสอบถามนี้จะใช้งานได้

สถานการณ์ที่สอง

ส่งคืนรายชื่อพนักงานที่มีงานค้างชำระ ต่อไปนี้คือลักษณะของแบบสอบถามใน 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();

พนักงานในแบบสอบถามนี้เป็นเขตข้อมูลของ คลาส 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

ใน Hibernate ปัญหานี้แก้ไขได้ด้วยความช่วยเหลือของพารามิเตอร์การค้นหาที่ส่งผ่านไปยังวัตถุ Query และใน HQL เอง พารามิเตอร์ดังกล่าวเขียนผ่านโคลอน:user: แต่เราจะพูดถึงเรื่องนี้ในภายหลัง