Muammoni tavsifi
Yuqorida aytganimizdek, LazyCollectionOption.EXTRA annotatsiyasida muammo bor — u har bitta obyekt uchun alohida so'rov yuboradi. Hibernate’ga tushuntirishimiz kerak, biz barcha ota obyektlar uchun dastlabki bolalar obyektlarini yuklashni xohlaymiz.
Hibernate ishlab chiquvchilari bu muammoni hal qilish uchun join fetch operatorini HQL’da taklif qilishdi.
HQL so'rov misoli:
select distinct task from Task t left join fetch t.employee order by t.deadline
Bu so'rovda hamma narsalar oddiy va qiyin. Keling, uni qismlarga bo'lib qurib ko'raylik.
Variant 1
Barcha Task obyektlarini yuklashni xohlaymiz, deadline bo'yicha saralangan holda. Bu so'rov shunday ko'rinadi:
select task from Task t order by t.deadline
Hozircha hammasi tushunarli. Lekin employee maydoni Task klassining Employee xodimlar kolleksiyasini saqlaydi, u EXTRA annotatsiyasi bilan belgilangan. Va bu kolleksiya obyektlari yuklanmaydi.
Variant 2
Task obyekti uchun bolalar obyektlarini yuklashni Hibernate’ga majburlaymiz.
select task from Task t join fetch t.employee order by t.deadline
Bu orqali biz so’rovimizda Task va Employee obektlarini ochiq-oydin bog’laymiz. Hibernate ularni allaqachon biladi, chunki bu maydonlar uchun @ManyToMany annotatsiyalaridan foydalanamiz.
Lekin join operatoriga ehtiyoj bor, bu esa fetch operatori bilan to'ldiriladi va join fetch hosil bo'ladi. Shu yo'l bilan biz Hibernate’ga Task.employee kolleksiyalaridagi obyektlarni bizning so'rovimizni bajarishda bazadan yuklashni ko'rsatamiz.
Variant 3
Avvalgi yechimda ba'zi muammolar bor. Birinchidan, join ishlatilgandan keyin SQL jadvallarda Employee bilan bog’liq bo’lmagan Task obyektlarini qaytarmaydi. Bu aynan inner join qanday ishlashini ko’rsatadi.
Shuning uchun biz join operatorini left bilan to'ldirib, uni left joinga aylantirishimiz kerak. Misol:
select task from Task t left join fetch t.employee order by t.deadline
Variant 4
Lekin bu hammasi emas. Agar kodda ko‘pdan-ko‘pga munosabatlar bo‘lsa, so‘rov natijalarida dublikatlar paydo bo‘ladi. Bitta task obyekti turli xodimlar (Employee obyektlari) bilan bog‘liq bo‘lishi mumkin.
Shuning uchun distinct kalit so'zini select so’zidan keyin qo‘shtirish kerak, shunda Task obyektlarining dublikatlaridan xalos bo‘lasiz.
select distinct task from Task t left join fetch t.employee order by t.deadline
Shunday qilib, 4 qadamda, biz boshlagan so'rovga erishdik. Java kodi esa hech qanday ajablanarli emas:
String hql = " select distinct task from Task t left join fetch t.employee order by t.deadline";
Query<Task> query = session.createQuery( hql, Task.class);
return query.list();
JOIN FETCH cheklovlari
Hech kim mukammal emas, JOIN FETCH operatori ham. Uning ko'p cheklovlari bor. Birinchisi - setMaxResults() va setFirstResult() metodlarini ishlatish.
JOIN FETCH operatori uchun Hibernate uchta jadvalni: employee, task va employee_taskni birlashtiradigan murakkab so'rov yaratadi. Aslida, bu xodimlar yoki vazifalar so'rovi emas, balki barcha ma'lum xodim-vazifa juftliklarining so'rovi.
Va SQL cheksiz holda LIMIT va OFFSET operatorlarini aynan shu xodim-vazifa juftliklariga qo'llashi mumkin. HQL so'rovining o'zi esa, biz aniq vazifalarni (Task) olishni xohlayotganimizni ko'rsatadi, agar FirstResult va MaxResult parametrlarini ajratib qo'ysak, ular aniq Task obyektlariga tegishli bo'lishi kerak.
Agar siz quyidagi kodni yozsangiz:
String hql = " select distinct task from Task t left join fetch t.employee order by t.deadline";
Query<Task> query = session.createQuery( hql, Task.class);
query.setFirstResult(0);
query.setMaxResults(1);
return query.list();
Hibernate FirstResult va MaxResultni SQL so'rovi uchun OFFSET va LIMIT parametrlari sifatida to'g'ri o'zgartira olmaydi.
Buning o'rniga u uchta ishni bajaradi:
- SQL so'rovi barcha ma'lumotlarni jadvallardan tanlaydi va ularni Hibernate’ga qaytaradi
- Hibernate o'z yodiga saqlab kerakli yozuvlarni tanlaydi va sizga qaytaradi
- Hibernate eslatma beradi
Eslatma quyidagicha bo'ladi:
WARN [org.hibernate.hql.internal.ast.QueryTranslatorImpl] HHH000104:
firstResult/maxResults specified with collection fetch; applying in memory!
GO TO FULL VERSION