5.1 Các hình thức giao tiếp trực tiếp khác nhau

Có một trường hợp thú vị và khá cụ thể khác về mối quan hệ giữa hai lớp Thực thể - mối quan hệ một đối một.

Tôi gọi trường hợp này là rất cụ thể, vì nó nói về các đối tượng Java nhiều hơn là cơ sở dữ liệu. Trong cơ sở dữ liệu, chỉ có hai tùy chọn cho mối quan hệ giữa các bảng:

  • Hàng của bảng chứa một liên kết đến id của một bảng khác.
  • Bảng dịch vụ được sử dụng cho mối quan hệ nhiều-nhiều.

Trong trường hợp các lớp Thực thể, có thể có các tùy chọn được mô tả bằng một số chú thích:

  • @Embedded
  • Một phía OneToOne
  • Song phương OneToOne
  • @MapsId

Dưới đây chúng tôi sẽ xem xét phổ biến nhất trong số họ.

5.2 Nhúng

Nhân tiện, chúng tôi đã xem xét tùy chọn liên lạc trực tiếp đơn giản nhất - đây là chú thích @Embedded. Trong trường hợp này, chúng ta có hai lớp được lưu trữ trong cùng một bảng trong cơ sở dữ liệu.

Giả sử chúng ta muốn lưu trữ địa chỉ của người dùng trong lớp 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;
}

Sau đó, chúng ta chỉ cần thêm một trường có địa chỉ này vào lớp Người dùng :


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

Hibernate sẽ làm phần còn lại: dữ liệu sẽ được lưu trữ trong một bảng, nhưng khi viết truy vấn HQL, bạn sẽ cần thao tác trên các trường lớp.

Ví dụ truy vấn HQL:

select from User where address.city = 'Paris'

5.3 Một bên OneToOne

Bây giờ hãy tưởng tượng tình huống: chúng tôi có một nhân viên bảng nguồn và một nhiệm vụ đề cập đến nhân viên. Nhưng chúng tôi biết chắc chắn rằng tối đa một nhiệm vụ có thể được chỉ định cho một người dùng. Sau đó, chúng ta có thể sử dụng chú thích để mô tả tình huống này @OneToOne.

Ví dụ:


@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;
}

Hibernate sẽ đảm bảo rằng không chỉ một tác vụ có một người dùng mà cả một người dùng chỉ có một tác vụ. Mặt khác, trường hợp này thực tế không khác gì trường hợp @ManyToOne.

5.4 Song phương Một Đối Một

Tùy chọn trước đó có thể hơi bất tiện, vì bạn thường muốn giao một nhân viên không chỉ một nhiệm vụ mà còn giao nhiệm vụ cho một nhân viên.

Để làm điều này, bạn có thể thêm trường EmployeeTask vào lớp Employee và cung cấp cho nó các chú thích chính xác.


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

Quan trọng!Bảng nhân viên không có trường task_id , thay vào đó, trường employee_id của bảng nhiệm vụ được sử dụng để thiết lập mối quan hệ giữa các bảng .

Thiết lập kết nối giữa các đối tượng trông như thế này:


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();

Để xóa liên kết, các liên kết cũng phải được xóa khỏi cả hai đối tượng:


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();