Meja layanan
Sekarang mari kita lihat kasus umum lainnya - banyak-ke-banyak. Bayangkan kita memiliki hubungan banyak-ke-banyak antara tugas dan karyawan :
- Satu karyawan di tabel karyawan dapat melakukan banyak tugas dari tabel tugas.
- Satu tugas dalam tabel tugas dapat ditugaskan ke beberapa karyawan.
Hubungan antara entitas ini disebut banyak-ke-banyak. Dan untuk mengimplementasikannya pada level SQL, kita memerlukan tabel layanan tambahan. Sebut saja, misalnya, employee_task.
Tabel employee_task hanya akan berisi dua kolom:
- identitas pegawai
- task_id
Setiap kali kami memberikan tugas tertentu kepada pengguna tertentu, baris baru akan ditambahkan ke tabel ini. Contoh:
identitas pegawai | task_id |
---|---|
1 | 1 |
1 | 2 |
2 | 3 |
Nah, tabel tugas harus kehilangan kolom employee_id nya . Masuk akal hanya jika tugas hanya dapat diberikan kepada satu karyawan. Jika tugas dapat diberikan ke beberapa karyawan, maka informasi ini harus disimpan di tabel layanan employee_task .
Hubungan Tingkat Tabel
Inilah tampilan tabel baru kita:
pengenal | nama | pekerjaan | gaji | usia | join_date |
---|---|---|---|---|---|
1 | Ivanov Ivan | Programmer | 100000 | 25 | 30-06-2012 |
2 | Petrov Petr | Programmer | 80000 | 23 | 12-08-2013 |
3 | Ivanov Sergey | Penguji | 40000 | tigapuluh | 01-01-2014 |
4 | Rabinovich Moisha | Direktur | 200000 | 35 | 12-05-2015 |
5 | Kirienko Anastasia | Manajer kantor | 40000 | 25 | 10-10-2015 |
6 | Vaska | Kucing | 1000 | 3 | 11-11-2018 |
Tabel karyawan ( tidak diubah ) :
Tabel ini memiliki kolom berikut:
- id INT
- nama VARCHAR
- pendudukan VARCHAR
- gaji INT
- usia INT
- TANGGAL_gabung _
Dan seperti inilah tampilan tabel tugas , kehilangan kolom employee_id (ditandai dengan warna merah):
pengenal | employee_id | nama | tenggat waktu |
---|---|---|---|
1 | 1 | Perbaiki bug di frontend | 01-06-2022 |
2 | 2 | Perbaiki bug di backend | 15-06-2022 |
3 | 5 | Beli kopi | 01-07-2022 |
4 | 5 | Beli kopi | 01-08-2022 |
5 | 5 | Beli kopi | 01-09-2022 |
6 | (BATAL) | Membersihkan kantor | (BATAL) |
7 | 4 | Menikmati hidup | (BATAL) |
8 | 6 | Menikmati hidup | (BATAL) |
Tabel ini sekarang hanya memiliki 3 kolom:
- id - nomor tugas unik (dan baris dalam tabel)
- employee_id - (dihapus)
- nama - nama dan deskripsi tugas
- tenggat waktu - waktu sampai tugas harus diselesaikan
Kami juga memiliki tabel layanan employee_task , tempat data employee_id telah bermigrasi dari tabel tugas:
identitas pegawai | task_id |
---|---|
1 | 1 |
2 | 2 |
5 | 3 |
5 | 4 |
5 | 5 |
(BATAL) | 6 |
4 | 7 |
6 | 8 |
Saya sengaja menyimpan sementara kolom yang dihapus di tabel tugas sehingga Anda dapat melihat bahwa data darinya telah dipindahkan ke tabel employee_task.
Poin penting lainnya adalah garis merah "(NULL) 6" di tabel employee_task. Saya telah menandainya dengan warna merah karena tidak akan ada di tabel employee_task .
Jika tugas 7 ditugaskan ke pengguna 4, maka harus ada baris (4, 7) di tabel employee_task.
Jika tugas 6 tidak diberikan kepada siapa pun, maka tidak akan ada catatan untuk itu di tabel employee_task. Inilah tampilan versi final dari tabel-tabel ini:
tabel tugas :
pengenal | nama | tenggat waktu |
---|---|---|
1 | Perbaiki bug di frontend | 01-06-2022 |
2 | Perbaiki bug di backend | 15-06-2022 |
3 | Beli kopi | 01-07-2022 |
4 | Beli kopi | 01-08-2022 |
5 | Beli kopi | 01-09-2022 |
6 | Membersihkan kantor | (BATAL) |
7 | Menikmati hidup | (BATAL) |
8 | Menikmati hidup | (BATAL) |
tabel employee_task:
identitas pegawai | task_id |
---|---|
1 | 1 |
2 | 2 |
5 | 3 |
5 | 4 |
5 | 5 |
4 | 7 |
6 | 8 |
Komunikasi di tingkat kelas Java
Tetapi dengan komunikasi pada level kelas-Entitas, kami memiliki urutan yang lengkap. Mari kita mulai dengan kabar baik.
Pertama, Hibernate memiliki anotasi @ManyToMany khusus yang memungkinkan Anda menjelaskan dengan baik kasus hubungan tabel banyak-ke-banyak.
Kedua, dua kelas Entitas masih cukup untuk kita. Kami tidak membutuhkan kelas untuk tabel layanan.
Inilah yang kelas kami akan terlihat seperti. Kelas Karyawan dalam bentuk aslinya:
@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 aslinya:
@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 menghilangkan kolom yang ada di contoh, tetapi saya akan menambahkan yang baru. Inilah yang mereka akan terlihat seperti. Kelas karyawan :
@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>();
}
Tampaknya semuanya rumit, tetapi sebenarnya semuanya sederhana.
Pertama, ia menggunakan anotasi @JoinTable (jangan bingung dengan @JoinColumn), yang menjelaskan tabel layanan employee_task.
Kedua, menjelaskan bahwa kolom task_id dari tabel employee_task mengacu pada kolom id dari tabel tugas.
Ketiga, dikatakan bahwa kolom employee_id dari tabel employee_task mengacu pada kolom id dari tabel employee.
Faktanya, dengan bantuan anotasi, kami menjelaskan data apa yang terkandung dalam tabel employee_task dan bagaimana Hibernate harus menginterpretasikannya.
Tapi sekarang kita dapat dengan mudah menambahkan (dan menghapus) tugas ke karyawan mana pun. Dan juga tambahkan pemain apa pun ke tugas apa pun.
Minta contoh
Mari tulis beberapa pertanyaan menarik untuk lebih memahami cara kerja bidang ManyToMany ini. Dan mereka bekerja persis seperti yang diharapkan.
Pertama, kode lama kami akan berfungsi tanpa perubahan, karena direktur memiliki bidang tugas sebelumnya:
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 menugaskan pemain lain untuk suatu tugas, maka akan 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! Sebagai hasil dari pelaksanaan permintaan ini, tidak hanya tugas yang akan memiliki direktur pelaksana, tetapi direktur juga akan memiliki tugas No. 101.
Pertama, fakta tentang hubungan antara direktur dan tugas di tabel employee_task akan disimpan sebagai string: (4,101).
Kedua, bidang yang ditandai dengan anotasi @ManyToMany adalah objek proksi, dan saat diakses, kueri basis data selalu dijalankan.
Jadi jika Anda menambahkan tugas ke karyawan dan menyimpan informasi tentang karyawan tersebut ke database, maka setelah itu tugas tersebut akan memiliki pelaksana baru dalam daftar pelaksana.