2.1 Jadval darajasida aloqa
Biz Hibernate yordamida kolleksiyalarni yordamchi jadvallarda qanday saqlanishini ko'rib chiqdik. Endi esa haqiqiy Entity-klasslarni saqlaydigan to'liq jadvallar o'rtasida qanday aloqalar tashkil qilinishini o'rganamiz.
Hibernate'da Entity-klasslar orasida to'rtta turdagi aloqalar mavjud:
- one-to-one
- one-to-many
- many-to-one
- many-to-many
Biz oddiyroq variantdan boshlaymiz – many-to-one.
Bunday jadval orasidagi aloqalarni SQL'da ko'rgan bo'lsang kerak. Mana bu odatda qanday ko'rinishda bo'ladi:
| id | name | occupation | salary | age | join_date |
|---|---|---|---|---|---|
| 1 | Ivanov Ivan | Dasturchi | 100000 | 25 | 2012-06-30 |
| 2 | Petrov Petr | Dasturchi | 80000 | 23 | 2013-08-12 |
| 3 | Ivanov Sergey | Tester | 40000 | 30 | 2014-01-01 |
| 4 | Rabinovich Moysha | Direktor | 200000 | 35 | 2015-05-12 |
| 5 | Kirienko Anastasiya | Ofis-menejer | 40000 | 25 | 2015-10-10 |
| 6 | Vas'ka | Mushuk | 1000 | 3 | 2018-11-11 |
Employee jadvali:
Bu jadvalda quyidagi ustunlar mavjud:
- id INT
- name VARCHAR
- occupation VARCHAR
- salary INT
- age INT
- join_date DATE
Bu yerda task jadvali ko'rinishi, xodimlarga berilgan vazifalarni saqlaydi:
| id | employee_id | name | deadline |
|---|---|---|---|
| 1 | 1 | Frontenddagi xatolarni tuzatish | 2022-06-01 |
| 2 | 2 | Backenddagi xatolarni 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 | Hayotni zavq bilan yashash | (NULL) |
| 8 | 6 | Hayotni zavq bilan yashash | (NULL) |
Bu jadvalda faqat 4 ta ustun mavjud:
- id – vazifaning unikal raqami (va jadvaldagi qator);
- employee_id – employee jadvalidan xodim ID'si, vazifa tayinlangan;
- name – vazifaning nomi va ta'rifi;
- deadline – vazifani bajarish kerak bo'lgan vaqt.
Biz ko'rayapmizki, task jadvalidagi ko'p qatorlar employee jadvalidagi bir yozuvga ishora qiladi. Bunday aloqa jadval darajasida ko'pdan-birga (many-to-one) deb ataladi.
2.2 Java-klass darajasida aloqa
Jadval darajasidagi aloqadan tashqari, Hibernate'da Entity-klasslar darajasida ham aloqa o'rnatishingiz mumkin. Bu @ManyToOne annotatsiyasi orqali amalga oshiriladi.
Ammo avvaliga shunchaki ikkita klass yaratamiz: Employee va EmployeeTask:
@Entity @Table(name="employee")
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;
}
Xodimlarning vazifalarini saqlash uchun ikkinchi klass:
@Entity @Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@Column(name="employee_id")
public Integer employeeId;
@Column(name="deadline")
public Date deadline;
}
Bu klasslar yaxshi, lekin ularning orasida hech qanday aloqa yo'q, bu EmployeeTask klassidagi employeeId maydonini Employee klassidagi id maydoniga ishora qilayotganini ko'rsatmaydi. Va bu xatoni endi tuzatamiz.
2.3 @ManyToOne annotatsiyasi.
Birinchidan, Javada biz odatda obyektlar (va ob'ektlarga havolalar) bilan ishlaymiz, ularning id'lari bilan emas. Shunday qilib, birinchi navbatda EmployeeTask klassida employeeId o'rniga Employee turidagi obyektga havola ko'rsatamiz. Mana bizning yangi klassimiz qanday ko'rinadi:
@Entity @Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@ManyToOne @JoinColumn(name = "employee_id")
public Employee employee;
@Column(name="deadline")
public Date deadline;
}
@ManyToOne annotatsiyasi yordamida biz EmployeeTask klassining ko'plab obyektlari bir Employee turidagi obyektga ishora qilishi mumkinligini ko'rsatdik. @JoinColumn annotatsiyasi yordamida esa biz Employee obyektining id'si qaysi ustunda saqlanishini ko'rsatdik.
2.4 So'rovlar misollari
Endi Hibernate bu kabi bog'langan klasslar bilan qanday ishlay olishini bir necha misollarda ko'rsatamiz.
Birinchi ssenariy
Keling, ma'lum bir foydalanuvchiga berilgan barcha vazifalarni bilib olish uchun so'rov yozamiz. Mana bu so'rov HQLda qanday ko'rinadi:
from EmployeeTask where employee.name = "Ivan Ivanovich"
Siz bog'langan klasslar maydonlariga nuqta orqali murojaat qilishingiz mumkin. Bu juda qulay. Lekin keling, bu so'rovni Java-kod sifatida yozamiz:
String hql = "from EmployeeTask where employee.name = :username";
Query<EmployeeTask> query = session.createQuery( hql, EmployeeTask.class);
query.setParameter("username", "Ivan Ivanovich");
List<EmployeeTask> resultLIst = query.list();
Ikkinchi ssenariy
Keling, muddati o'tgan vazifalar mavjud bo'lgan xodimlar ro'yxatini qaytaradigan so'rov yozamiz. Vazifa muddati o'tgan, agar uning muddati allaqachon o'lgan bo'lsa. Mana bu so'rov SQLda qanday ko'rinadi:
SELECT DISTINCT employee.*
FROM task JOIN employee ON task.employee_id = employee.id
WHERE task.deadline < CURDATE();
DISTINCT belgilangan, chunki bir foydalanuvchiga ko'p vazifalar tayinlangan bo'lishi mumkin.
Endi bu so'rovni HQLda yozamiz:
select distinct employee from EmployeeTask where deadline < CURDATE();
Employee bu so'rovda – bu EmployeeTask klassining maydoni
Uchinchi vaziyat
Ishga tayinlanmagan barcha vazifalarni direktor ustiga tayinlash. SQLdagi so'rov mana shunday ko'rinadi:
UPDATE task SET employee_id = 4 WHERE employee_id IS NULL
Endi bu so'rovni HQLda yozamiz:
update EmployeeTask set employee = :user where employee is null
So'nggi so'rov eng murakkab. Bizga direktorning ID'si kerak, lekin EmployeeTask klassida id qo'yish mumkin bo'lgan maydon mavjud emas, buning o'rniga Employee turidagi obyektga havola qiladigan maydon mavjud.
Employee director = session.get(Employee.class, 4);
String hql = "update EmployeeTask set employee = :user where employee is null";
Query<EmployeeTask> query = session.createQuery(hql, EmployeeTask.class);
query.setParameter("user", director);
query.executeUpdate();
GO TO FULL VERSION