Meja servis

Sekarang mari kita lihat satu lagi kes biasa - banyak-ke-banyak. Mari kita bayangkan bahawa kita mempunyai hubungan banyak-ke-banyak antara tugas dan pekerja :

  • Seorang pekerja dalam jadual pekerja boleh melakukan banyak tugas dari jadual tugas.
  • Satu tugas dalam jadual tugas boleh diberikan kepada beberapa pekerja.

Hubungan antara entiti ini dipanggil banyak-ke-banyak. Dan untuk melaksanakannya di peringkat SQL, kami memerlukan jadual perkhidmatan tambahan. Mari kita panggilnya, sebagai contoh, employee_task.

Jadual employee_task hanya akan mengandungi dua lajur:

  • ID pekerja
  • id_tugas

Setiap kali kami memberikan tugasan khusus kepada pengguna tertentu, baris baharu akan ditambahkan pada jadual ini. Contoh:

ID pekerja id_tugas
1 1
1 2
2 3

Nah, jadual tugas sepatutnya kehilangan lajur employee_id . Ia masuk akal hanya jika tugas itu hanya boleh diberikan kepada seorang pekerja. Jika tugas boleh diberikan kepada beberapa pekerja, maka maklumat ini mesti disimpan dalam jadual perkhidmatan employee_task .

Hubungan Aras Meja

Begini rupa jadual baharu kami:

ID nama pekerjaan gaji umur tarikh menyertai
1 Ivanov Ivan Pengaturcara 100000 25 30-06-2012
2 Petrov Petr Pengaturcara 80000 23 2013-08-12
3 Ivanov Sergey Penguji 40000 tiga puluh 2014-01-01
4 Rabinovich Moisha Pengarah 200000 35 12-05-2015
5 Kirienko Anastasia Pengurus pejabat 40000 25 2015-10-10
6 Vaska Kucing 1000 3 2018-11-11

Jadual pekerja ( tidak diubah ) :

Jadual ini mempunyai lajur berikut:

  • id INT
  • nama VARCHAR
  • pekerjaan VARCHAR
  • gaji INT
  • umur INT
  • join_date DATE

Dan ini adalah bagaimana jadual tugas kelihatan seperti , kehilangan lajur employee_id (ditandakan dengan warna merah):

ID id_pekerja nama tarikh akhir
1 1 Betulkan pepijat pada bahagian hadapan 2022-06-01
2 2 Betulkan pepijat pada bahagian belakang 15-06-2022
3 5 Beli kopi 2022-07-01
4 5 Beli kopi 2022-08-01
5 5 Beli kopi 2022-09-01
6 (NULL) Bersihkan pejabat (NULL)
7 4 Nikmati kehidupan (NULL)
8 6 Nikmati kehidupan (NULL)

Jadual ini kini hanya mempunyai 3 lajur:

  • id - nombor tugas unik (dan baris dalam jadual)
  • id_pekerja - (dialih keluar)
  • nama - nama dan huraian tugas
  • tarikh akhir - masa sehingga tugas itu mesti diselesaikan

Kami juga mempunyai jadual perkhidmatan employee_task , yang mana data employee_id telah berhijrah daripada jadual tugas:

ID pekerja id_tugas
1 1
2 2
5 3
5 4
5 5
(NULL) 6
4 7
6 8

Saya sengaja menyimpan sementara lajur yang dipadamkan dalam jadual tugas supaya anda dapat melihat bahawa data daripadanya telah berpindah ke jadual pekerja_tugas.

Satu lagi perkara penting ialah garis merah "(NULL) 6" dalam jadual employee_task. Saya telah menandainya dengan warna merah kerana ia tidak akan berada dalam jadual employee_task .

Jika tugasan 7 diberikan kepada pengguna 4, maka harus ada baris (4, 7) dalam jadual employee_task.

Jika tugasan 6 tidak diberikan kepada sesiapa, maka tidak akan ada rekod untuknya dalam jadual employee_task. Inilah rupa versi akhir jadual ini:

jadual tugas :

ID nama tarikh akhir
1 Betulkan pepijat pada bahagian hadapan 2022-06-01
2 Betulkan pepijat pada bahagian belakang 15-06-2022
3 Beli kopi 2022-07-01
4 Beli kopi 2022-08-01
5 Beli kopi 2022-09-01
6 Bersihkan pejabat (NULL)
7 Nikmati kehidupan (NULL)
8 Nikmati kehidupan (NULL)

jadual tugas_pekerja:

ID pekerja id_tugas
1 1
2 2
5 3
5 4
5 5
4 7
6 8

Komunikasi di peringkat kelas Java

Tetapi dengan komunikasi di peringkat kelas Entiti, kami mempunyai susunan yang lengkap. Mari kita mulakan dengan berita gembira.

Pertama, Hibernate mempunyai anotasi @ManyToMany khas yang membolehkan anda menerangkan dengan baik kes perhubungan jadual banyak-ke-banyak.

Kedua, dua kelas Entiti masih mencukupi untuk kami. Kami tidak memerlukan kelas untuk meja perkhidmatan.

Inilah rupa kelas kami. Kelas Pekerja dalam bentuk asalnya:

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

Dan kelas EmployeeTask dalam bentuk asalnya:

@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 anotasi

Saya akan meninggalkan medan sedia ada dalam contoh, tetapi saya akan menambah yang baharu. Inilah rupa mereka. Kelas pekerja :

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

}

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

}

Nampaknya semuanya rumit, tetapi sebenarnya semuanya mudah.

Pertama, ia menggunakan anotasi @JoinTable (jangan dikelirukan dengan @JoinColumn), yang menerangkan jadual perkhidmatan employee_task.

Kedua, ia menerangkan bahawa lajur task_id jadual employee_task merujuk kepada lajur id jadual tugas.

Ketiga, ia mengatakan bahawa lajur id_pekerja bagi jadual tugas_pekerja merujuk kepada lajur id bagi jadual pekerja.

Malah, dengan bantuan anotasi, kami menerangkan data yang terkandung dalam jadual employee_task dan cara Hibernate harus mentafsirkannya.

Tetapi kini kita boleh dengan mudah menambah (dan memadam) tugasan kepada mana-mana pekerja. Dan juga menambah mana-mana pelaku untuk sebarang tugas.

Minta contoh

Mari tulis beberapa pertanyaan menarik untuk lebih memahami cara medan ManyToMany ini berfungsi. Dan mereka berfungsi seperti yang diharapkan.

Pertama, kod lama kami akan berfungsi tanpa perubahan, kerana pengarah mempunyai medan tugas sebelum ini:

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

Kedua, jika kita ingin menetapkan pelaku lain untuk beberapa tugas, maka lebih mudah untuk melakukan ini:

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

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

Penting! Hasil daripada melaksanakan permintaan ini, bukan sahaja tugas itu akan mempunyai pengarah-pelaksana, tetapi pengarah juga akan mempunyai tugas No. 101.

Pertama, fakta tentang hubungan antara pengarah dan tugas dalam jadual employee_task akan disimpan sebagai rentetan: (4,101).

Kedua, medan yang ditandakan dengan anotasi @ManyToMany ialah objek proksi, dan apabila ia diakses, pertanyaan pangkalan data sentiasa dilaksanakan.

Jadi jika anda menambah tugas kepada pekerja dan menyimpan maklumat tentang pekerja ke pangkalan data, maka selepas itu tugas itu akan mempunyai pelaksana baharu dalam senarai pelaksana.