@ManyToMany

All lectures for UZ purposes
Daraja, Dars
Mavjud

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.

Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION