2.1 การเชื่อมโยงในระดับตาราง
เราได้เห็นวิธีที่ไฮเบอร์เนตจัดเก็บคอลเลกชันในตารางเสริม ตอนนี้ มาดูวิธีจัดระเบียบความสัมพันธ์ระหว่างตารางแบบเต็มที่เก็บคลาสเอนทิตีจริง
มีความสัมพันธ์สี่ประเภทระหว่างคลาสเอนทิตีในไฮเบอร์เนต:
- หนึ่งต่อหนึ่ง
- หนึ่งต่อหลาย
- หลายต่อหนึ่ง
- หลายต่อหลาย
และเราจะเริ่มการวิเคราะห์ด้วยตัวเลือกที่ง่ายที่สุด- หลายต่อหนึ่ง
คุณได้พบกับความสัมพันธ์ระหว่างตารางใน SQL แล้ว นี่คือลักษณะที่ปรากฏ:
รหัส | ชื่อ | อาชีพ | เงินเดือน | อายุ | เข้าร่วม_วันที่ |
---|---|---|---|---|---|
1 | อีวานอฟ อีวาน | โปรแกรมเมอร์ | 100,000 | 25 | 2555-06-30 |
2 | เปตรอฟ เปตรอฟ | โปรแกรมเมอร์ | 80000 | 23 | 2013-08-12 |
3 | อีวานอฟ เซอร์เกย์ | เทสเตอร์ | 40000 | สามสิบ | 2014-01-01 |
4 | ราบิโนวิช มอยชา | ผู้อำนวยการ | 200,000 | 35 | 2015-05-12 |
5 | คิเรียนโก อนาสตาเซีย | ผู้จัดการสำนักงาน | 40000 | 25 | 2015-10-10 |
6 | วาสก้า | แมว | 1,000 | 3 | 2018-11-11 |
ตารางพนักงาน:
ตารางนี้มีคอลัมน์ต่อไปนี้:
- รหัส INT
- ชื่อวาร์ชาร์
- อาชีพ VARCHAR
- INT เงินเดือน
- อายุ INT
- join_dateวันที่
และนี่คือลักษณะของตารางงานซึ่งมีงานสำหรับพนักงาน มีลักษณะดังนี้:
รหัส | รหัสพนักงาน | ชื่อ | วันกำหนดส่ง |
---|---|---|---|
1 | 1 | แก้ไขข้อบกพร่องในส่วนหน้า | 2022-06-01 |
2 | 2 | แก้ไขข้อบกพร่องในส่วนหลัง | 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 – รหัสพนักงานจากตารางพนักงานที่มอบหมายงาน
- ชื่อ – ชื่อและคำอธิบายของงาน
- เส้นตาย - เวลาที่ต้องทำงานให้เสร็จ
เราเห็นว่าหลายแถวในตารางงานสามารถอ้างถึงรายการเดียวในตารางพนักงาน ความสัมพันธ์ระดับตารางดังกล่าวเรียกว่ากลุ่มต่อหนึ่ง
2.2 ความสัมพันธ์กับระดับคลาส Java
นอกจากการสื่อสารในระดับตารางแล้ว คุณยังสามารถจัดระเบียบการสื่อสารในระดับคลาสเอนทิตีในไฮเบอร์เนตได้อีกด้วย สิ่งนี้ทำได้ด้วยคำอธิบาย@ManyToOne
ประกอบ
แต่ก่อนอื่นมาสร้างสองคลาส: EmployeeและEmployeeTask :
@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;
}
ทั้งหมดนี้เป็นไปได้ด้วยดีกับคลาสเหล่านี้ แต่ไม่มีความสัมพันธ์ระหว่างคลาสเหล่านี้ที่จะสะท้อนข้อเท็จจริงที่ว่าฟิลด์ EmployeeId ของคลาส EmployeeTask อ้างอิงถึงฟิลด์ id ของคลาส Employee ถึงเวลาแก้ไขแล้ว
2.3 คำอธิบายประกอบ @ManyToOne
ประการแรก ใน Java เราคุ้นเคยกับการดำเนินการกับวัตถุ (และการอ้างอิงวัตถุ) มากกว่ารหัสของมัน ก่อนอื่น แทนที่จะเป็นฟิลด์ EmployeeId ในคลาส EmployeeTask ให้ชี้ไปที่วัตถุประเภท Employee นี่คือลักษณะของชั้นเรียนใหม่ของเรา:
@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
ประกอบ เราระบุว่าคอลัมน์ใดในตารางของเราที่มีการจัดเก็บ 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();
พนักงานในแบบสอบถามนี้เป็นเขตข้อมูลของคลาส 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();
GO TO FULL VERSION