5.1 รูปแบบต่างๆ ของการสื่อสารตัวต่อตัว

มีอีกกรณีหนึ่งที่น่าสนใจและค่อนข้างเฉพาะเจาะจงของความสัมพันธ์ระหว่างสองคลาสของเอนทิตี นั่นคือความสัมพันธ์แบบหนึ่งต่อหนึ่ง

ฉันเรียกกรณีนี้ว่าเฉพาะเจาะจงมาก เนื่องจากเป็นเรื่องเกี่ยวกับวัตถุ Java มากกว่าฐานข้อมูล ในฐานข้อมูล มีเพียงสองตัวเลือกสำหรับความสัมพันธ์ระหว่างตาราง:

  • แถวของตารางมีลิงก์ไปยังรหัสของตารางอื่น
  • ตารางบริการใช้สำหรับความสัมพันธ์แบบกลุ่มต่อกลุ่ม

ในกรณีของคลาสเอนทิตี อาจมีตัวเลือกที่อธิบายโดยคำอธิบายประกอบหลายรายการ:

  • @ฝัง
  • OneToOne ด้านเดียว
  • ทวิภาคีวันทูวัน
  • @แผนที่รหัส

ด้านล่างเราจะพิจารณาความนิยมสูงสุดของพวกเขา

5.2 แบบฝังตัว

อย่างไรก็ตาม เราได้พิจารณา ตัวเลือกการสื่อสาร แบบตัวต่อตัวที่ง่ายที่สุด แล้ว นั่นคือคำอธิบาย @Embeddedประกอบ ในกรณีนี้ เรามีสองคลาสที่จัดเก็บไว้ในตารางเดียวกันในฐานข้อมูล

สมมติว่าเราต้องการจัดเก็บที่อยู่ของผู้ใช้ใน คลาส UserAddress :


@Embeddable
class UserAddress {
   @Column(name="user_address_country")
   public String country;
   @Column(name="user_address_city")
   public String city;
   @Column(name="user_address_street")
   public String street;
   @Column(name="user_address_home")
   public String home;
}

จากนั้นเราต้องเพิ่มฟิลด์ที่มีที่อยู่นี้ใน คลาส User :


@Entity
@Table(name="user")
class User {
   @Column(name="id")
   public Integer id;
 
   @Embedded
   public UserAddress address;
 
   @Column(name="created_date")
   public Date createdDate;
}

Hibernate จะทำส่วนที่เหลือ: ข้อมูลจะถูกจัดเก็บไว้ในตารางเดียว แต่เมื่อเขียนแบบสอบถาม HQL คุณจะต้องดำเนินการกับฟิลด์คลาส

ตัวอย่างแบบสอบถาม HQL:

select from User where address.city = 'Paris'

5.3 วันทูวันด้านเดียว

ลองนึกภาพสถานการณ์ตอนนี้: เรามีพนักงานตารางต้นทางและงานที่อ้างถึงพนักงาน แต่เรารู้แน่นอนว่าสามารถมอบหมายงานให้กับผู้ใช้หนึ่งคนได้สูงสุดหนึ่งงาน จากนั้นเราสามารถใช้คำอธิบายประกอบเพื่ออธิบายสถานการณ์นี้@OneToOneได้

ตัวอย่าง:


@Entity
@Table(name="task")
class EmployeeTask {
   @Column(name="id")
   public Integer id;
 
   @Column(name="name")
   public String description;
 
   @OneToOne
   @JoinColumn(name = "employee_id")
   public Employee employee;
 
   @Column(name="deadline")
   public Date deadline;
}

ไฮเบอร์เนตจะตรวจสอบให้แน่ใจว่าไม่ได้มีเพียงงานเดียวที่มีผู้ใช้เพียงคนเดียว แต่ยังรวมถึงผู้ใช้หนึ่งรายที่มีงานเดียวเท่านั้น มิฉะนั้น กรณีนี้ก็ไม่ต่างจาก@ManyToOne.

5.4 ทวิภาคีวันทูวัน

ตัวเลือกก่อนหน้านี้อาจไม่สะดวกเล็กน้อย เพราะบ่อยครั้งที่คุณต้องการมอบหมายงานให้พนักงาน ไม่เพียงแต่งานเท่านั้น แต่ยังมอบหมายงานให้พนักงานด้วย

ในการทำเช่นนี้ คุณสามารถเพิ่มฟิลด์ EmployeeTask ให้กับคลาสพนักงานและใส่คำอธิบายประกอบที่ถูกต้อง


@Entity
@Table(name="employee")
class Employee {
   @Column(name="id")
   public Integer id;
 
   @OneToOne(cascade = CascadeType.ALL, mappedBy="employee")
   private EmployeeTask task;
}

สำคัญ!ตารางพนักงานไม่มี เขต ข้อมูลรหัสงานแต่ จะใช้เขต ข้อมูลรหัสพนักงาน ของ ตารางงาน แทนเพื่อสร้างความสัมพันธ์ระหว่าง ตาราง

การสร้างการเชื่อมต่อระหว่างวัตถุมีลักษณะดังนี้:


Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employee = director;
director.task = task;
 
session.update(task);
session.flush();

หากต้องการลบลิงก์ จะต้องลบลิงก์ออกจากออบเจ็กต์ทั้งสองด้วย:


Employee director = session.find(Employee.class, 4);
EmployeeTask task = director.task;
 
task.employee = null;
session.update(task);
 
director.task = null;
session.update(director);
 
session.flush();