โต๊ะบริการ
ทีนี้มาดูกรณีทั่วไปอีกกรณีหนึ่ง - แบบกลุ่มต่อกลุ่ม ลองจินตนาการว่าเรามี ความสัมพันธ์ แบบกลุ่ม ต่อกลุ่มระหว่างงานและพนักงาน :
- พนักงานหนึ่งคนในตารางพนักงานสามารถทำงานหลายอย่างได้จากตารางงาน
- งานหนึ่งงานในตารางงานสามารถกำหนดให้กับพนักงานหลายคนได้
ความสัมพันธ์ระหว่างเอนทิตีนี้เรียกว่ากลุ่มต่อกลุ่ม และเพื่อนำไปใช้ในระดับ SQL เราจำเป็นต้องมีตารางบริการเพิ่มเติม ตัวอย่างเช่น เรียกมันว่า Employee_task
ตาราง Employee_task จะมีเพียงสองคอลัมน์:
- รหัสพนักงาน
- task_id
แต่ละครั้งที่เรามอบหมายงานเฉพาะให้กับผู้ใช้รายใดรายหนึ่ง แถวใหม่จะถูกเพิ่มลงในตารางนี้ ตัวอย่าง:
รหัสพนักงาน | task_id |
---|---|
1 | 1 |
1 | 2 |
2 | 3 |
ตารางงานควรสูญเสียคอลัมน์ Employee_id เป็นเรื่องที่สมเหตุสมผลหากสามารถมอบหมายงานให้กับพนักงานเพียงคนเดียวเท่านั้น หากสามารถมอบหมายงานให้กับพนักงานหลายคนได้ ข้อมูลนี้จะต้องเก็บไว้ในตารางบริการพนักงาน
ความสัมพันธ์ระดับตาราง
นี่คือลักษณะของตารางใหม่ของเรา:
รหัส | ชื่อ | อาชีพ | เงินเดือน | อายุ | เข้าร่วม_วันที่ |
---|---|---|---|---|---|
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วันที่
และนี่คือลักษณะของตารางงานสูญเสียคอลัมน์ Employee_id (ทำเครื่องหมายด้วยสีแดง):
รหัส | พนักงาน_id | ชื่อ | วันกำหนดส่ง |
---|---|---|---|
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 | ใช้ชีวิตให้สนุก | (โมฆะ) |
ตารางนี้มีเพียง 3 คอลัมน์:
- id - หมายเลขงานเฉพาะ (และแถวในตาราง)
- Employee_id - (ลบออกแล้ว)
- ชื่อ - ชื่อและรายละเอียดของงาน
- เส้นตาย - เวลาที่ต้องทำงานให้เสร็จ
เรายังมีตารางบริการ Employee_taskซึ่งข้อมูล Employee_id ถูกย้ายจากตารางงาน:
รหัสพนักงาน | task_id |
---|---|
1 | 1 |
2 | 2 |
5 | 3 |
5 | 4 |
5 | 5 |
(โมฆะ) | 6 |
4 | 7 |
6 | 8 |
ฉันตั้งใจบันทึกคอลัมน์ที่ถูกลบชั่วคราวในตารางงาน เพื่อให้คุณเห็นว่าข้อมูลจากคอลัมน์นั้นถูกย้ายไปยังตาราง Employee_task แล้ว
จุดสำคัญอีกจุดหนึ่งคือเส้นสีแดง"(NULL) 6"ในตาราง Employee_task ฉันทำเครื่องหมายเป็นสี แดงเพราะจะไม่อยู่ในตาราง Employee_task
หากมอบหมายงาน 7 ให้กับผู้ใช้ 4 ควรมีแถว (4, 7) ในตาราง Employee_task
หากไม่ได้มอบหมายงาน 6 ให้กับใคร ก็จะไม่มีการบันทึกในตาราง Employee_task นี่คือลักษณะสุดท้ายของตารางเหล่านี้:
ตารางงาน :
รหัส | ชื่อ | วันกำหนดส่ง |
---|---|---|
1 | แก้ไขข้อบกพร่องในส่วนหน้า | 2022-06-01 |
2 | แก้ไขข้อบกพร่องในส่วนหลัง | 2022-06-15 |
3 | ซื้อกาแฟ | 2022-07-01 |
4 | ซื้อกาแฟ | 2022-08-01 |
5 | ซื้อกาแฟ | 2022-09-01 |
6 | ทำความสะอาดสำนักงาน | (โมฆะ) |
7 | ใช้ชีวิตให้สนุก | (โมฆะ) |
8 | ใช้ชีวิตให้สนุก | (โมฆะ) |
ตารางพนักงาน_task:
รหัสพนักงาน | task_id |
---|---|
1 | 1 |
2 | 2 |
5 | 3 |
5 | 4 |
5 | 5 |
4 | 7 |
6 | 8 |
การสื่อสารในระดับคลาส Java
แต่ด้วยการสื่อสารในระดับ Entity-classs เรามีคำสั่งที่สมบูรณ์ เริ่มต้นด้วยข่าวดี
อันดับแรก Hibernate มีคำอธิบายประกอบพิเศษ@ManyToManyที่ช่วยให้คุณสามารถอธิบายกรณีของความสัมพันธ์ของตารางแบบกลุ่มต่อกลุ่มได้
ประการที่สอง คลาสเอนทิตีสองคลาสยังเพียงพอสำหรับเรา เราไม่ต้องการคลาสสำหรับตารางบริการ
ชั้นเรียนของเราจะมีลักษณะดังนี้ คลาสพนักงานในรูปแบบดั้งเดิม:
@Entity
@Table(name="user")
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;
}
และ คลาส EmployeeTaskในรูปแบบดั้งเดิม:
@Entity
@Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@Column(name="deadline")
public Date deadline;
}
คำอธิบายประกอบ @ManyToMany
ฉันจะละเว้นฟิลด์ที่มีอยู่ในตัวอย่าง แต่ฉันจะเพิ่มฟิลด์ใหม่ นี่คือสิ่งที่พวกเขาจะมีลักษณะ ระดับพนักงาน :
@Entity
@Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name="employee_task",
joinColumns= @JoinColumn(name="employee_id", referencedColumnName="id"),
inverseJoinColumns= @JoinColumn(name="task_id", referencedColumnName="id") )
private Set<EmployeeTask> tasks = new HashSet<EmployeeTask>();
}
และ คลาส EmployeeTask :
@Entity
@Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name="employee_task",
joinColumns= @JoinColumn(name="task_id", referencedColumnName="id"),
inverseJoinColumns= @JoinColumn(name=" employee_id", referencedColumnName="id") )
private Set<Employee> employees = new HashSet<Employee>();
}
ดูเหมือนว่าทุกอย่างจะซับซ้อน แต่ในความเป็นจริงทุกอย่างนั้นง่าย
ขั้นแรก ใช้ คำอธิบายประกอบ @JoinTable (เพื่อไม่ให้สับสนกับ @JoinColumn) ซึ่งอธิบายถึงตารางบริการของ Employee_task
ประการที่สอง อธิบายว่าคอลัมน์ task_id ของตาราง Employee_task อ้างอิงถึงคอลัมน์ ID ของตารางงาน
ประการที่สาม ระบุว่าคอลัมน์ Employee_id ของตาราง Employee_task อ้างอิงถึงคอลัมน์ ID ของตารางพนักงาน
ในความเป็นจริง ด้วยความช่วยเหลือของคำอธิบายประกอบ เราได้อธิบายว่าข้อมูลใดบ้างที่อยู่ในตาราง Employee_task และ Hibernate ควรตีความอย่างไร
แต่ตอนนี้เราสามารถเพิ่ม (และลบ) งานให้กับพนักงานได้อย่างง่ายดาย และยังเพิ่มนักแสดงให้กับงานใด ๆ
ขอตัวอย่าง
ลองเขียนแบบสอบถามที่น่าสนใจสองสามข้อเพื่อทำความเข้าใจวิธีการทำงานของช่อง ManyToMany เหล่านี้ให้ดียิ่งขึ้น และทำงานได้ตรงตามที่คาดไว้
ขั้นแรก รหัสเก่าของเราจะทำงานโดยไม่มีการเปลี่ยนแปลง เนื่องจากผู้อำนวยการมีช่องงานมาก่อน:
EmployeeTask task1 = new EmployeeTask();
task1.description = "Do Something Important";
session.persist(task1);
EmployeeTask task2 = new EmployeeTask();
task2.description = "Nothing to do";
session.persist(task2);
session.flush();
Employee director = session.find(Employee.class, 4);
director.tasks.add(task1);
director.tasks.add(task2);
session.update(director);
session.flush();
ประการที่สอง หากเราต้องการมอบหมายงานบางอย่างให้กับนักแสดงคนอื่น การทำเช่นนี้จะง่ายยิ่งขึ้นไปอีก:
Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employees.add(director);
session.update(task);
session.flush();
สำคัญ! จากการดำเนินการตามคำขอนี้ ไม่เพียงแต่งานจะมีผู้ดำเนินการ-ผู้อำนวยการเท่านั้น แต่ผู้อำนวยการจะมีงานหมายเลข 101 ด้วย
อันดับแรก ข้อเท็จจริงเกี่ยวกับความสัมพันธ์ระหว่างผู้อำนวยการและงานในตาราง Employee_task จะถูกจัดเก็บเป็นสตริง: (4,101)
ประการที่สอง ฟิลด์ที่ทำเครื่องหมายด้วย คำอธิบายประกอบ @ManyToManyเป็นวัตถุพร็อกซี และเมื่อเข้าถึงฟิลด์เหล่านี้ การสืบค้นฐานข้อมูลจะถูกดำเนินการเสมอ
ดังนั้น หากคุณเพิ่มงานให้กับพนักงานและบันทึกข้อมูลเกี่ยวกับพนักงานลงในฐานข้อมูล หลังจากนั้น งานจะมีตัวดำเนินการใหม่ในรายการตัวดำเนินการ