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!