Beskrivelse av problemet

Som vi sa ovenfor, har LazyCollectionOption.EXTRA -kommentaren et problem - den utfører en separat forespørsel til databasen for hvert objekt. Vi må på en eller annen måte forklare Hibernate at vi vil at den umiddelbart skal laste inn alle underordnede objekter for våre overordnede objekter.

Utviklerne av Hibernate har kommet opp med en løsning på dette problemet, join appetch- operatøren i HQL.

Eksempel på HQL-søk:

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

I denne spørringen er alt enkelt og komplekst på samme tid. La oss prøve å konstruere den del for del.

valg 1

Vi ønsker å laste ned alle objekteroppgave, sortert etter frist. Slik vil forespørselen se ut:

select task from Task t order by t.deadline

Mens alt er klart. Men feltetansattav oppgaveklassen vil inneholde en samling av ansatte merket med EKSTRA merknaden . Og gjenstandene til denne samlingen vil ikke bli lastet.

Alternativ 2

Tving dvalemodus til å laste underordnede objekter for et objektoppgave.

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

Med hjelp binder vi eksplisitt oppgave- og ansatt-enhetene i søket vårt. Hibernate vet dette allerede fordi vi bruker @ManyToMany- kommentarene på disse feltene.

Men vi trenger en join -setning for å fullføre den med en appetch -setning for å få en join-henting . Dette er hvordan vi forteller Hibernate at objektene i Task.employee-samlingene må lastes fra databasen når forespørselen vår utføres.

Alternativ 3

Den forrige løsningen har noen få bugs. For det første, etter bruk av join, vil ikke SQL returnere objekter til ossoppgave, som ikke har noen objekter knyttet til seg i Employee-tabellen. Dette er nøyaktig hvordan indre sammenføyning fungerer .

Så vi må utvide sammenføyningen vår med en venstre operatør og gjøre den om til en venstre sammenføyning . Eksempel:

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

Alternativ 4

Men det er ikke alt. Hvis forholdet mellom entiteter i koden din er mange-til-kan, vil det være duplikater i søkeresultatene. Det samme objektetoppgavefinnes på ulike ansatte (Ansattobjekter).

Så du må legge til det distinkte nøkkelordet etter det valgte ordet for å bli kvitt det dupliserte Task-objektet.

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

Slik kom vi i 4 trinn til forespørselen som vi startet med. Vel, Java-koden vil se ganske forventet ut:

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

BLI MED HENT Begrensninger

Ingen er perfekte. JOIN FETCH-erklæring også. Den har ganske mange begrensninger. Og den første bruker metodene setMaxResults() og setFirstResult() .

For JOIN FETCH-setningen vil vår Hibernate generere en svært kompleks spørring der vi kombinerer tre tabeller til én: ansatt, oppgave og ansatt_oppgave. Dette er faktisk ikke en forespørsel for ansatte eller oppgaver, men for alle kjente ansatt-oppgavepar.

Og SQL kan bruke sine LIMIT- og OFFSET-setninger på akkurat det spørringen av ansatt-oppgavepar. Samtidig følger det tydelig av HQL-spørringen at vi ønsker å få nøyaktig oppgaver (Task), og hvis vi redistribuerer våre FirstResult- og MaxResult-parametere, så bør de referere spesifikt til Task-objekter.

Hvis du skriver kode slik:

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

Da vil ikke Hibernate kunne konvertere FirstResult og MaxResult til OFFSET- og LIMIT-parametrene til SQL-spørringen.

I stedet vil den gjøre tre ting:

  • SQL-spørring vil generelt velge alle data fra tabellen og returnere dem til dvalemodus
  • Hibernate vil velge de nødvendige postene i minnet og returnere dem til deg
  • Hibernate vil gi en advarsel

Advarselen vil være noe slikt:

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