Paglalarawan ng problema

Gaya ng sinabi namin sa itaas, may problema ang LazyCollectionOption.EXTRA annotation - nagsasagawa ito ng hiwalay na kahilingan sa database para sa bawat object. Kailangan naming ipaliwanag sa Hibernate na kahit papaano ay gusto naming i-load agad ang lahat ng object ng bata para sa mga object ng magulang namin.

Ang mga developer ng Hibernate ay nakabuo ng solusyon sa problemang ito, ang join fetch operator sa HQL.

Halimbawa ng query ng HQL:

select distinct task from Task t left join fetch t.employee order by t.deadline

Sa query na ito, ang lahat ay simple at kumplikado sa parehong oras. Subukan nating buuin ito nang paisa-isa.

Opsyon 1

Nais naming i-download ang lahat ng mga bagaygawain, inayos ayon sa deadline. Narito ang magiging hitsura ng kahilingang iyon:

select task from Task t order by t.deadline

Habang malinaw ang lahat. Ngunit ang laranganempleadong klase ng Gawain ay maglalaman ng koleksyon ng mga Empleyado na may anotasyon na may EXTRA na anotasyon . At ang mga bagay ng koleksyon na ito ay hindi mai-load.

Opsyon 2

Pilitin ang Hibernate na i-load ang mga child object para sa isang objectgawain.

select task from Task t join fetch t.employee order by t.deadline

Sa tulong, tahasan naming pinagsasama ang mga entity ng Task at Employee sa aming query. Alam na ito ng Hibernate dahil ginagamit namin ang @ManyToMany annotation sa mga field na ito.

Ngunit kailangan namin ng join statement para makumpleto ito ng fetch statement para makakuha ng join fetch . Ito ay kung paano namin sasabihin sa Hibernate na ang mga bagay sa mga koleksyon ng Task.employee ay kailangang i-load mula sa database kapag ang aming kahilingan ay naisakatuparan.

Opsyon 3

Ang nakaraang solusyon ay may ilang mga bug. Una, pagkatapos gamitin ang pagsali, hindi ibabalik ng SQL ang mga bagay sa amingawain, na walang mga bagay na nauugnay sa kanila sa talahanayan ng Empleyado. Ito ay eksakto kung paano gumagana ang panloob na pagsali .

Kaya kailangan nating dagdagan ang ating pagsali sa isang kaliwang operator at gawin itong kaliwang pagsali . Halimbawa:

select task from Task t left join fetch t.employee order by t.deadline

Opsyon 4

Ngunit hindi lang iyon. Kung sa iyong code ang ugnayan sa pagitan ng mga entity ay many-to-may, magkakaroon ng mga duplicate sa mga resulta ng query. Ang parehong bagaygawainay matatagpuan sa iba't ibang empleyado (Employee objects).

Kaya kailangan mong idagdag ang natatanging keyword pagkatapos ng piling salita upang maalis ang duplicate na bagay na Gawain.

select distinct task from Task t left join fetch t.employee order by t.deadline

Ito ay kung paano sa 4 na hakbang narating namin ang kahilingan kung saan kami nagsimula. Well, ang Java code ay magmumukhang inaasahan:

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();

SUMALI SA FETCH Mga Limitasyon

Walang perpekto. JOIN FETCH statement din. Mayroon itong medyo ilang mga limitasyon. At ang una ay gumagamit ng setMaxResults() at setFirstResult() na mga pamamaraan .

Para sa pahayag na JOIN FETCH, bubuo ang aming Hibernate ng napakakomplikadong query kung saan pinagsasama namin ang tatlong talahanayan sa isa: empleyado, gawain at employee_task. Sa katunayan, hindi ito isang kahilingan para sa mga empleyado o mga gawain, ngunit para sa lahat ng kilalang pares ng empleyado-gawain.

At maaaring ilapat ng SQL ang LIMIT at OFFSET na mga pahayag nito sa eksaktong query na iyon ng mga pares ng empleyado-gawain. Kasabay nito, malinaw na sumusunod ito mula sa query ng HQL na gusto naming makakuha ng eksaktong mga gawain (Task), at kung muling ipamahagi namin ang aming mga parameter ng FirstResult at MaxResult, dapat silang partikular na sumangguni sa mga bagay na Gawain.

Kung sumulat ka ng code tulad nito:

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();

Kung gayon ang Hibernate ay hindi magagawang i-convert nang tama ang FirstResult at MaxResult sa OFFSET at LIMIT na mga parameter ng SQL query.

Sa halip, gagawa ito ng tatlong bagay:

  • Sa pangkalahatan, pipiliin ng SQL query ang lahat ng data mula sa talahanayan at ibabalik ito sa Hibernate
  • Pipiliin ng hibernate ang mga kinakailangang tala sa memorya nito at ibabalik ang mga ito sa iyo
  • Maglalabas ng babala ang hibernate

Ang babala ay magiging ganito:

WARN [org.hibernate.hql.internal.ast.QueryTranslatorImpl] HHH000104: 
firstResult/maxResults specified with collection fetch; applying in memory!