bảng dịch vụ

Bây giờ hãy xem xét một trường hợp phổ biến khác - nhiều-nhiều. Hãy tưởng tượng rằng chúng ta có mối quan hệ nhiều-nhiều giữa các nhiệm vụ và nhân viên :

  • Một nhân viên trong bảng nhân viên có thể thực hiện nhiều nhiệm vụ từ bảng nhiệm vụ.
  • Một nhiệm vụ trong bảng nhiệm vụ có thể được giao cho nhiều nhân viên.

Mối quan hệ này giữa các thực thể được gọi là nhiều-nhiều. Và để triển khai nó ở cấp độ SQL, chúng tôi cần một bảng dịch vụ bổ sung. Ví dụ, hãy gọi nó là employee_task.

Bảng employee_task sẽ chỉ chứa hai cột:

  • Mã hiệu công nhân
  • task_id

Mỗi khi chúng tôi giao một nhiệm vụ cụ thể cho một người dùng cụ thể, một hàng mới sẽ được thêm vào bảng này. Ví dụ:

Mã hiệu công nhân task_id
1 1
1 2
2 3

Chà, bảng nhiệm vụ sẽ mất cột employee_id của nó . Nó chỉ có ý nghĩa nếu nhiệm vụ chỉ có thể được giao cho một nhân viên. Nếu nhiệm vụ có thể được giao cho một số nhân viên, thì thông tin này phải được lưu trữ trong bảng dịch vụ employee_task .

Mối quan hệ cấp độ bảng

Đây là những gì các bảng mới của chúng tôi sẽ trông như thế nào:

nhận dạng tên nghề nghiệp lương tuổi ngày tham gia
1 Ivanov Ivan lập trình viên 100000 25 30-06-2012
2 Petrov Petr lập trình viên 80000 23 2013-08-12
3 Ivanov Serge Kiểm thử 40000 ba mươi 2014-01-01
4 Rabinovich Moisha Giám đốc 200000 35 2015-05-12
5 kirienko anastasia Quản lý văn phòng 40000 25 2015-10-10
6 Vaska Con mèo 1000 3 2018-11-11

Bảng nhân viên ( không thay đổi ) :

Bảng này có các cột sau:

  • id INT
  • tên VARCHAR
  • nghề nghiệp VARCHAR
  • tiền lương
  • tuổi INT
  • join_date NGÀY

Và đây là bảng nhiệm vụ trông như thế nào , mất cột employee_id (được đánh dấu màu đỏ):

nhận dạng nhân viên_id tên thời hạn
1 1 Sửa lỗi ở frontend 2022-06-01
2 2 Sửa lỗi trên backend 2022-06-15
3 5 Mua cà phê 2022-07-01
4 5 Mua cà phê 2022-08-01
5 5 Mua cà phê 2022-09-01
6 (VÔ GIÁ TRỊ) Dọn dẹp văn phòng (VÔ GIÁ TRỊ)
7 4 Tận hưởng cuộc sống (VÔ GIÁ TRỊ)
số 8 6 Tận hưởng cuộc sống (VÔ GIÁ TRỊ)

Bảng này hiện chỉ có 3 cột:

  • id - số nhiệm vụ duy nhất (và các hàng trong bảng)
  • employee_id - (đã xóa)
  • tên - tên và mô tả của nhiệm vụ
  • thời hạn - thời gian cho đến khi nhiệm vụ phải được hoàn thành

Chúng ta cũng có bảng dịch vụ employee_task , trong đó dữ liệu employee_id đã được di chuyển từ bảng tác vụ:

Mã hiệu công nhân task_id
1 1
2 2
5 3
5 4
5 5
(VÔ GIÁ TRỊ) 6
4 7
6 số 8

Tôi cố ý lưu tạm thời cột đã xóa trong bảng nhiệm vụ để bạn có thể thấy rằng dữ liệu từ cột đó đã chuyển sang bảng employee_task.

Một điểm quan trọng khác là dòng màu đỏ "(NULL) 6" trong bảng employee_task. Tôi đã đánh dấu nó màu đỏ vì nó sẽ không có trong bảng employee_task .

Nếu nhiệm vụ 7 được giao cho người dùng 4, thì phải có một hàng (4, 7) trong bảng employee_task.

Nếu nhiệm vụ 6 không được giao cho bất kỳ ai, thì sẽ không có bản ghi nào cho nhiệm vụ đó trong bảng employee_task. Đây là phiên bản cuối cùng của các bảng này sẽ trông như thế nào:

bảng nhiệm vụ :

nhận dạng tên thời hạn
1 Sửa lỗi ở frontend 2022-06-01
2 Sửa lỗi trên backend 2022-06-15
3 Mua cà phê 2022-07-01
4 Mua cà phê 2022-08-01
5 Mua cà phê 2022-09-01
6 Dọn dẹp văn phòng (VÔ GIÁ TRỊ)
7 Tận hưởng cuộc sống (VÔ GIÁ TRỊ)
số 8 Tận hưởng cuộc sống (VÔ GIÁ TRỊ)

bảng employee_task:

Mã hiệu công nhân task_id
1 1
2 2
5 3
5 4
5 5
4 7
6 số 8

Giao tiếp ở cấp lớp Java

Nhưng với giao tiếp ở cấp độ của các lớp Thực thể, chúng tôi có một trật tự hoàn chỉnh. Hãy bắt đầu với những tin tốt.

Đầu tiên, Hibernate có một chú thích @ManyToMany đặc biệt cho phép bạn mô tả rõ trường hợp của mối quan hệ bảng nhiều-nhiều.

Thứ hai, hai lớp Thực thể vẫn đủ cho chúng tôi. Chúng tôi không cần một lớp cho bảng dịch vụ.

Đây là những gì các lớp học của chúng tôi sẽ trông như thế nào. Lớp Nhân viên ở dạng ban đầu:

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

Và lớp EmployeeTask ở dạng ban đầu:

@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 chú thích

Tôi sẽ bỏ qua các trường hiện có trong các ví dụ, nhưng tôi sẽ thêm các trường mới. Đây là những gì họ sẽ trông như thế nào. Hạng nhân viên :

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

}

Và lớp 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>();

}

Có vẻ như mọi thứ đều phức tạp, nhưng thực tế mọi thứ đều đơn giản.

Đầu tiên, nó sử dụng chú thích @JoinTable (đừng nhầm với @JoinColumn), mô tả bảng dịch vụ employee_task.

Thứ hai, nó mô tả rằng cột task_id của bảng employee_task đề cập đến cột id của bảng nhiệm vụ.

Thứ ba, nó nói rằng cột employee_id của bảng employee_task đề cập đến cột id của bảng employee.

Trên thực tế, với sự trợ giúp của các chú thích, chúng tôi đã mô tả dữ liệu nào được chứa trong bảng employee_task và cách Hibernate nên diễn giải dữ liệu đó.

Nhưng bây giờ chúng ta có thể dễ dàng thêm (và xóa) một nhiệm vụ cho bất kỳ nhân viên nào. Và cũng có thể thêm bất kỳ người biểu diễn nào vào bất kỳ nhiệm vụ nào.

yêu cầu ví dụ

Hãy viết một số truy vấn thú vị để hiểu rõ hơn về cách hoạt động của các trường ManyToMany này. Và chúng hoạt động chính xác như mong đợi.

Đầu tiên, mã cũ của chúng tôi sẽ hoạt động mà không có thay đổi nào, vì trước đây giám đốc đã có trường nhiệm vụ:

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

Thứ hai, nếu chúng ta muốn chỉ định một người thực hiện một nhiệm vụ nào đó, thì việc này thậm chí còn dễ dàng hơn:

Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employees.add(director);

session.update(task);
session.flush();

Quan trọng! Do thực hiện yêu cầu này, không chỉ nhiệm vụ sẽ có người thực thi-giám đốc mà cả giám đốc sẽ có nhiệm vụ số 101.

Đầu tiên, thực tế về mối quan hệ giữa giám đốc và nhiệm vụ trong bảng employee_task sẽ được lưu trữ dưới dạng một chuỗi: (4,101).

Thứ hai, các trường được đánh dấu bằng chú thích @ManyToMany là các đối tượng proxy và khi chúng được truy cập, một truy vấn cơ sở dữ liệu luôn được thực thi.

Vì vậy, nếu bạn thêm một nhiệm vụ cho một nhân viên và lưu thông tin về nhân viên đó vào cơ sở dữ liệu, thì sau đó, nhiệm vụ đó sẽ có một người thực thi mới trong danh sách những người thực hiện.