Beskrivelse af problemet

Som vi sagde ovenfor, har LazyCollectionOption.EXTRA -annotationen et problem - den udfører en separat anmodning til databasen for hvert objekt. Vi skal på en eller anden måde forklare Hibernate, at vi ønsker, at den straks skal indlæse alle underordnede objekter for vores overordnede objekter.

Udviklerne af Hibernate har fundet en løsning på dette problem, join-hente- operatøren i HQL.

Eksempel på HQL-forespørgsel:

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

I denne forespørgsel er alt simpelt og komplekst på samme tid. Lad os prøve at konstruere det stykke for stykke.

Mulighed 1

Vi ønsker at downloade alle objekteropgave, sorteret efter deadline. Sådan ser anmodningen ud:

select task from Task t order by t.deadline

Mens alt er klart. Men feltetmedarbejderaf opgaveklassen vil indeholde en samling af medarbejdere, der er kommenteret med den EKSTRA annotering . Og objekterne i denne samling vil ikke blive indlæst.

Mulighed 2

Tving dvaletilstand til at indlæse underordnede objekter for et objektopgave.

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

Med hjælp binder vi eksplicit opgave- og medarbejderenhederne i vores forespørgsel. Hibernate ved allerede dette, fordi vi bruger @ManyToMany- annoteringerne på disse felter.

Men vi har brug for en join- sætning for at fuldføre den med en fetch -sætning for at få en join-hentning . Sådan fortæller vi Hibernate, at objekterne i Task.employee-samlingerne skal indlæses fra databasen, når vores anmodning udføres.

Mulighed 3

Den tidligere løsning har et par fejl. For det første, efter at have brugt join, returnerer SQL ikke objekter til osopgave, som ikke har nogen objekter knyttet til sig i tabellen Medarbejder. Det er præcis sådan indre sammenføjning fungerer .

Så vi er nødt til at udvide vores sammenføjning med en venstre operatør og forvandle den til en venstre sammenføjning . Eksempel:

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

Mulighed 4

Men det er ikke alt. Hvis forholdet mellem entiteter i din kode er mange-til-kan, så vil der være dubletter i forespørgselsresultaterne. Det samme objektopgavekan findes på forskellige medarbejdere (Medarbejderobjekter).

Så du skal tilføje det særskilte søgeord efter det valgte ord for at slippe af med det duplikerede opgaveobjekt.

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

Sådan kom vi i 4 trin til den forespørgsel, som vi startede med. Nå, Java-koden vil se ret forventet ud:

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 Begrænsninger

Ingen er perfekt. JOIN FETCH-erklæring også. Det har en del begrænsninger. Og den første bruger metoderne setMaxResults() og setFirstResult() .

For JOIN FETCH-sætningen vil vores Hibernate generere en meget kompleks forespørgsel, hvor vi kombinerer tre tabeller til én: medarbejder, opgave og medarbejder_opgave. Faktisk er dette ikke en anmodning om medarbejdere eller opgaver, men for alle kendte medarbejder-opgavepar.

Og SQL kan anvende sine LIMIT- og OFFSET-sætninger på præcis den forespørgsel af medarbejder-opgavepar. Samtidig følger det tydeligt af HQL-forespørgslen, at vi ønsker at få præcis opgaver (Task), og hvis vi omdistribuerer vores FirstResult- og MaxResult-parametre, så skal de referere specifikt til Task-objekter.

Hvis du skriver kode som denne:

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

Så vil Hibernate ikke være i stand til korrekt at konvertere FirstResult og MaxResult til OFFSET og LIMIT parametrene for SQL-forespørgslen.

I stedet vil den gøre tre ting:

  • SQL-forespørgsel vil generelt vælge alle data fra tabellen og returnere dem til Hibernate
  • Hibernate vil vælge de nødvendige poster i sin hukommelse og returnere dem til dig
  • Hibernate udsender en advarsel

Advarslen vil være sådan her:

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