A probléma leírása
Ahogy fentebb említettük, a LazyCollectionOption.EXTRA annotációval van egy probléma – minden objektumhoz külön kérést hajt végre az adatbázis felé. Valahogy el kell magyaráznunk a Hibernate-nak, hogy azt akarjuk, hogy azonnal betöltse az összes utódobjektumot a szülőobjektumokhoz.
A Hibernate fejlesztői megoldást találtak erre a problémára, a join fetch operátort a HQL-ben.
Példa a HQL lekérdezésre:
select distinct task from Task t left join fetch t.employee order by t.deadline
Ebben a lekérdezésben minden egyszerre egyszerű és összetett. Próbáljuk meg darabonként felépíteni.
1.opció
Minden objektumot le akarunk töltenifeladat, határidő szerint rendezve. Így nézne ki a kérés:
select task from Task t order by t.deadline
Miközben minden világos. De a mezőmunkavállalóa Feladat osztályban az EXTRA megjegyzéssel ellátott alkalmazottak gyűjteményét fogja tartalmazni . És ennek a gyűjteménynek az objektumai nem töltődnek be.
2. lehetőség
A hibernált állapot kényszerítése az objektum utódobjektumainak betöltésérefeladat.
select task from Task t join fetch t.employee order by t.deadline
Segítségével kifejezetten összekapcsoljuk a Task és Employee entitásokat a lekérdezésünkben. A Hibernate már tudja ezt, mert ezeken a mezőken a @ManyToMany megjegyzéseket használjuk .
De szükségünk van egy join utasításra , hogy kiegészítsük a fetch utasítással , hogy megkapjuk a join fetch-et . Így mondjuk el a Hibernate-nak, hogy a Task.employee gyűjteményekben lévő objektumokat be kell tölteni az adatbázisból, amikor a kérésünk végrehajtódik.
3. lehetőség
Az előző megoldásnak van néhány hibája. Először is, a join használata után az SQL nem ad vissza objektumokat nekünkfeladat, amelyekhez nincsenek objektumok társítva az Employee táblában. A belső összekapcsolás pontosan így működik .
Tehát ki kell bővítenünk a csatlakozásunkat egy bal oldali operátorral , és bal oldali összekapcsolássá kell alakítanunk . Példa:
select task from Task t left join fetch t.employee order by t.deadline
4. lehetőség
De ez még nem minden. Ha a kódban az entitások közötti kapcsolat sok-majális, akkor a lekérdezés eredménye duplikált. Ugyanaz a tárgyfeladatkülönböző alkalmazottakon (Employee objects) találhatók.
Tehát hozzá kell adnia a külön kulcsszót a kijelölő szó után, hogy megszabaduljon az ismétlődő Task objektumtól.
select distinct task from Task t left join fetch t.employee order by t.deadline
Így 4 lépésben eljutottunk ahhoz a kéréshez, amivel indultunk. Nos, a Java kód nagyon vártnak tűnik:
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 Korlátozások
Senki sem tökéletes. JOIN FETCH utasítás is. Jó néhány korlátja van. És az első a setMaxResults() és setFirstResult() metódusok használata .
A JOIN FETCH utasításhoz a Hibernate egy nagyon összetett lekérdezést fog generálni, amelyben három táblát egyesítünk egybe: munkavállaló, feladat és munkavállaló_feladat. Valójában ez nem az alkalmazottakra vagy feladatokra vonatkozik, hanem az összes ismert alkalmazott-feladat párra.
Az SQL pedig a LIMIT és OFFSET utasításait pontosan az alkalmazott-feladat párok lekérdezésére tudja alkalmazni. Ugyanakkor a HQL lekérdezésből egyértelműen az következik, hogy pontosan feladatokat szeretnénk kapni (Task), és ha a FirstResult és MaxResult paramétereinket újraosztjuk, akkor azok kifejezetten a Task objektumokra vonatkozzanak.
Ha így írsz kódot:
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();
Ekkor a Hibernate nem tudja megfelelően konvertálni a FirstResult és a MaxResult paramétereket az SQL lekérdezés OFFSET és LIMIT paramétereire.
Ehelyett három dolgot fog tenni:
- Az SQL lekérdezés általában az összes adatot kiválasztja a táblából, és visszaküldi a hibernált állapotba
- A Hibernate kiválasztja a szükséges rekordokat a memóriájában, és visszaküldi azokat Önnek
- A Hibernate figyelmeztetést ad ki
A figyelmeztetés valahogy így fog szólni:
WARN [org.hibernate.hql.internal.ast.QueryTranslatorImpl] HHH000104:
firstResult/maxResults specified with collection fetch; applying in memory!
GO TO FULL VERSION