Xizmat jadvali
Endi yana bir tez-tez uchraydigan holatni ko'rib chiqamiz – many-to-many. Keling, bizda vazifalar va xodimlar o'rtasida bo'lish-ular munosabati mavjudligini tasavvur qilaylik:
- employee jadvalidagi bitta ishchi task jadvalidan ko'plab vazifalarni bajarishi mumkin.
- task jadvalidagi bitta vazifa bir nechta xodimlarga tayinlanishi mumkin.
Bunday elementlar orasidagi bog'lanish many-to-many deb ataladi. Va biz buni SQL darajasida amalga oshirish uchun qo'shimcha xizmat jadvali kerak bo'ladi. Uni, masalan, employee_task deb ataymiz.
employee_task jadvali faqat ikkita ustunni o'z ichiga oladi:
- employee_id
- task_id
Har safar ma'lum bir vazifani ma'lum bir foydalanuvchiga tayinlaganimizda, ushbu jadvalga yangi qator qo'shiladi. Misol:
| employee_id | task_id |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 2 | 3 |
Xo'sh, task jadvali employee_id ustunidan mahrum bo'lishi kerak. U ma'lum bo'lgan holatdagina mazmunli, agar vazifa faqat bitta xodimga tayinlangan bo'lsa. Agar vazifa bir nechta xodimlarga tayinlanadigan bo'lsa, bu ma'lumotlar employee_task xizmat jadvalida saqlanishi kerak.
Jadval darajasidagi bog'lanish
Mana bizning yangi jadvallarimiz qanday ko'rinadi:
| id | name | occupation | salary | age | join_date |
|---|---|---|---|---|---|
| 1 | Ivanov Ivan | Dasturchi | 100000 | 25 | 2012-06-30 |
| 2 | Petrov Pyotr | Dasturchi | 80000 | 23 | 2013-08-12 |
| 3 | Ivanov Sergey | Testlovchi | 40000 | 30 | 2014-01-01 |
| 4 | Rabinovich Moysha | Direktor | 200000 | 35 | 2015-05-12 |
| 5 | Kiriyenko Anastasiya | Ofis-menejer | 40000 | 25 | 2015-10-10 |
| 6 | Vaska | Mushuk | 1000 | 3 | 2018-11-11 |
employee jadvali (o'zgarmagan):
Ushbu jadvalda quyidagi ustunlar mavjud:
- id INT
- name VARCHAR
- occupation VARCHAR
- salary INT
- age INT
- join_date DATE
Mana task jadvali qanday ko'rinadi, employee_id ustunini yo'qotdi (qizil bilan belgilangan):
| id | emploee_id | name | deadline |
|---|---|---|---|
| 1 | 1 | Frontenddagi xatoni tuzatish | 2022-06-01 |
| 2 | 2 | Backenddagi xatoni tuzatish | 2022-06-15 |
| 3 | 5 | Kofe sotib olish | 2022-07-01 |
| 4 | 5 | Kofe sotib olish | 2022-08-01 |
| 5 | 5 | Kofe sotib olish | 2022-09-01 |
| 6 | (NULL) | Ofisni tozalash | (NULL) |
| 7 | 4 | Hayotdan zavqlanish | (NULL) |
| 8 | 6 | Hayotdan zavqlanish | (NULL) |
Endi bu jadvalda faqat 3 ta ustun mavjud:
- id – vazifaning noyob raqami (va jadvalidagi qatorning)
- employee_id – (yo'qotilgan)
- name – vazifa nomi va tavsifi
- deadline – vazifani bajarish kerak bo'lgan vaqt
Shuningdek, bizda employee_id haqidagi ma'lumotlar task jadvalidan employee_task xizmat jadvaliga o'tgan:
| employee_id | task_id |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 5 | 3 |
| 5 | 4 |
| 5 | 5 |
| (NULL) | 6 |
| 4 | 7 |
| 6 | 8 |
Men maqsadni amalga oshirish uchun qizil rang bilan belgilangan "(NULL) 6" qatorni vaqtincha saqlab qoldim, shunda siz task jadvalidan ma'lumotlar employee_task jadvaliga qanday o'tganini ko'rishingiz mumkin.
Agar task 7 foydalanuvchi 4 ustida ishlayotgan bo'lsa, employee_task jadvalida qator bo'lishi kerak: (4, 7).
Agar task 6 hech qanday foydalanuvchiga tayinlanmagan bo'lsa, employee_task jadvali uchun hech qanday yozuv bo'lmaydi. Mana, ushbu jadvallarning yakuniy versiyalari qanday ko'rinadi:
task jadvali:
| id | name | deadline |
|---|---|---|
| 1 | Frontenddagi xatoni tuzatish | 2022-06-01 |
| 2 | Backenddagi xatoni tuzatish | 2022-06-15 |
| 3 | Kofe sotib olish | 2022-07-01 |
| 4 | Kofe sotib olish | 2022-08-01 |
| 5 | Kofe sotib olish | 2022-09-01 |
| 6 | Ofisni tozalash | (NULL) |
| 7 | Hayotdan zavqlanish | (NULL) |
| 8 | Hayotdan zavqlanish | (NULL) |
employee_task jadvali:
| employee_id | task_id |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 5 | 3 |
| 5 | 4 |
| 5 | 5 |
| 4 | 7 |
| 6 | 8 |
Java-klasslar darajasidagi bog'lanish
Aytishim kerakki, Java-klasslar darajasidagi bog'lanishlar juda oson. Keling, yaxshi xabarlarni boshlaylik.
Birinchidan, Hibernate mavjud bo'lib, maxsus annotatsiya mavjud @ManyToMany, bu jadval munosabatlarini many-to-many bilan yaxshi tasvirlash imkonini beradi.
Ikkinchidan, bizga hali ham faqat ikki xil Entity-klasslar kifoya. Xizmat jadvallari uchun alohida klass kerak emas.
Mana bizning klasslarimiz qanday ko'rinadi. Employee klassining boshlang'ich ko'rinishi:
@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;
}
Va EmployeeTask klassining boshlang'ich ko'rinishi:
@Entity
@Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@Column(name="deadline")
public Date deadline;
}
Annotatsiya @ManyToMany
Misollarda mavjud ustunlarni ko'rsatmayman, lekin yangilarini qo'shaman. Mana ular qanday ko'rinadi. Employee klassi:
@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>();
}
Va EmployeeTask klassi:
@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>();
}
Hammasi qiyin tuyulishi mumkin, lekin aslida bu juda oddiy.
Birinchidan, bu yerda @JoinTable annotatsiyasi ishlatiladi (uni @JoinColumn bilan adashtirmang), bu employee_task xizmat jadvalini tavsiflaydi.
Ikkinchidan, u yerda task jadvalidagi id ustuniga employee_task jadvalining task_id ustuni mos kelishi eslatiladi.
Uchinchidan, u yerda employee jadvalidagi id ustuniga employee_task jadvalidagi employee_id ustuni mos kelishi eslatiladi.
Biz annotatsiyalar yordamida employee_task jadvalida qanday ma'lumotlar saqlanishini va Hibernate ularni qanday talqin qilishi kerakligini tasvirladik.
Biz endi xodimga vazifa qo'shish (va olib tashlash) juda oson, shuningdek har qanday xodimga har qanday vazifani tayinlashimiz mumkin.
So'rovlar misollari
Keling, bir nechta qiziqarli so'rovlar yozaylik, bu ManyToMany maydonlari qanday ishlashini yaxshiroq tushunish uchun. Ular kutganimizdek ishlaydi.
Birinchidan, bizning eski kodimiz o'zgarmasdan ishlaydi, chunki direktorda ilgari tasks maydoni mavjud edi:
EmployeeTask task1 = new EmployeeTask();
task1.description = "Muhim ish qilish";
session.persist(task1);
EmployeeTask task2 = new EmployeeTask();
task2.description = "Hech nima qilmaslik";
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();
Ikkinchidan, agar biz biror vazifani boshqa bir xodimga tayinlamoqchi bo'lsak, bu juda oson:
Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employees.add(director);
session.update(task);
session.flush();
Muqim! Ushbu so'rov o'z ishini bajargandan so'ng, vazifaga nafaqat direktorni ijrochi sifatida qo'shadi, balki direktor uchun ham 101 raqamli vazifa paydo bo'ladi.
Birinchidan, employee_task jadvalidagi direktor va vazifa o'rtasidagi munosabatlar haqiqatini qator ko'rinishida saqlanadi: (4,101).
Ikkinchidan, @ManyToMany annotatsiyasi bilan belgilangan maydonlar proxy-obyektlardir va ularga murojaat qilganda har doim ma'lumotlar bazasiga so'rov amalga oshiriladi.
Shu sababdan, vazifani xodimga qo'shish va uni ma'lumotlar bazasida saqlash uchun, vazifa ichidagi xodimlar ro'yxatida yangi ijrochi paydo bo'ladi.
GO TO FULL VERSION