โต๊ะบริการ

ทีนี้มาดูกรณีทั่วไปอีกกรณีหนึ่ง - แบบกลุ่มต่อกลุ่ม ลองจินตนาการว่าเรามี ความสัมพันธ์ แบบกลุ่ม ต่อกลุ่มระหว่างงานและพนักงาน :

  • พนักงานหนึ่งคนในตารางพนักงานสามารถทำงานหลายอย่างได้จากตารางงาน
  • งานหนึ่งงานในตารางงานสามารถกำหนดให้กับพนักงานหลายคนได้

ความสัมพันธ์ระหว่างเอนทิตีนี้เรียกว่ากลุ่มต่อกลุ่ม และเพื่อนำไปใช้ในระดับ 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เป็นวัตถุพร็อกซี และเมื่อเข้าถึงฟิลด์เหล่านี้ การสืบค้นฐานข้อมูลจะถูกดำเนินการเสมอ

ดังนั้น หากคุณเพิ่มงานให้กับพนักงานและบันทึกข้อมูลเกี่ยวกับพนักงานลงในฐานข้อมูล หลังจากนั้น งานจะมีตัวดำเนินการใหม่ในรายการตัวดำเนินการ