Hurtigguide til EntityManager # getReference ()

1. Introduksjon

De getReference () metoden for EntityManager klasse har vært en del av JPA-spesifikasjonen siden den første versjonen. Imidlertid forvirrer denne metoden noen utviklere fordi oppførselen varierer avhengig av den underliggende leverandøren av utholdenhet.

I denne opplæringen skal vi forklare hvordan du bruker getReference () metode i Dvalemodus EntityManager.

2. EntityManager Hent operasjoner

Først og fremst vil vi se på hvordan vi kan hente enheter ved hjelp av deres primære nøkler. Uten å skrive noen spørsmål, EntityManager gir oss to grunnleggende metoder for å oppnå dette.

2.1. finne()

finne() er den vanligste metoden for å hente enheter:

Game game = entityManager.find (Game.class, 1L); 

Denne metoden initialiserer enheten når vi ber om det.

2.2. getReference ()

I likhet med finne() metode, getReference () er også en annen måte å hente enheter på:

Game game = entityManager.getReference (Game.class, 1L); 

Imidlertid er gjenstanden returnert en enhetsproxy som bare har primærnøkkelfeltet initialisert. De andre feltene forblir ikke innstilt med mindre vi la dem lat.

Deretter, la oss se hvordan disse to metodene oppfører seg i forskjellige scenarier.

3. Et eksempel på en brukssak

For å demonstrere EntityManager hente operasjoner, vi lager to modeller, Spill og Spiller, som vårt domene at mange spillere kan være involvert i det samme spillet.

3.1. Domenemodell

La oss først definere en enhet som heter Spill:

@Entity offentlig klassespill {@Id privat Lang id; privat strengnavn; // standard konstruktører, getters, setters} 

Deretter definerer vi vår Spiller enhet:

@Entity offentlig klassespiller {@Id privat Lang id; privat strengnavn; // standard konstruktører, getters, setters} 

3.2. Konfigurere relasjoner

Vi må konfigurere en @ManyToOne forhold fra Spiller til Spill. Så la oss legge til en spill eiendom til vår Spiller enhet:

@ManyToOne privat spill spill; 

4. Test tilfeller

Før vi begynner å skrive testmetodene våre, er det en god praksis å definere testdataene våre separat:

entityManager.getTransaction (). start (); entityManager.persist (nytt spill (1L, "spill 1")); entityManager.persist (nytt spill (2L, "spill 2")); entityManager.persist (ny spiller (1L, "spiller 1")); entityManager.persist (ny spiller (2L, "Player 2")); entityManager.persist (ny spiller (3L, "Player 3")); entityManager.getTransaction (). commit (); 

I tillegg, for å undersøke underliggende SQL-spørsmål, bør vi konfigurere dvalemodus dvalemodus.show_sql eiendom i vår persistence.xml:

4.1. Oppdaterer enhetsfelt

Først vil vi sjekke den vanligste måten å oppdatere en enhet ved å bruke finne() metode.

Så la oss skrive en testmetode for å hente Spill enheten først, og deretter bare oppdatere den Navn felt:

Spill game1 = entityManager.find (Game.class, 1L); game1.setName ("Spill oppdatert 1"); entityManager.persist (game1); 

Å kjøre testmetoden viser oss de utførte SQL-spørringene:

Dvalemodus: velg game0_.id som id1_0_0_, game0_.name som name2_0_0_ fra Game game0_ hvor game0_.id =? Dvalemodus: oppdater spillets navn =? hvor id =? 

Som vi merker, de Å VELGE spørring ser unødvendig ut i et slikt tilfelle. Siden vi ikke trenger å lese noe felt i Spill enhet før oppdateringsoperasjonen vår, lurer vi på om det bare er noen måte å utføre OPPDATER spørsmål.

Så, la oss se hvordan getReference () metoden oppfører seg i samme scenario:

Spill game1 = entityManager.getReference (Game.class, 1L); game1.setName ("Spill oppdatert 2"); entityManager.persist (game1); 

Overraskende, resultatet av den løpende testmetoden er fortsatt det samme, og vi ser Å VELGE spørringen gjenstår.

Som vi kan se, utfører dvalemodus en Å VELGE spørring når vi bruker getReference () for å oppdatere et enhetsfelt.

Derfor, bruker getReference () metoden unngår ikke det ekstra Å VELGE spørring hvis vi utfører noen setter av enhetsproxy-feltene.

4.2. Slette enheter

Et lignende scenario kan skje når vi utfører slettingsoperasjoner.

La oss definere to andre testmetoder for å slette en Spiller enhet:

Player player2 = entityManager.find (Player.class, 2L); entityManager.remove (spiller2); 
Player player3 = entityManager.getReference (Player.class, 3L); entityManager.remove (player3); 

Å kjøre disse testmetodene viser oss de samme spørsmålene:

Dvalemodus: velg spiller0_.id som id1_1_0_, spiller0_.game_id som game_id3_1_0_, player0_.name som navn2_1_0_, game1_.id som id1_0_1_, game1_.name som name2_0_1_ fra Player player0_ venstre ytre bli med Game Game1_ på player0_.game_id = game_. .id =? Dvalemodus: slett fra Player der id =? 

På samme måte, for sletteoperasjoner, er resultatet likt. Selv om vi ikke leser noen felt i Spiller enhet utfører dvalemodus en ekstra Å VELGE spørring også.

Derfor, det er ingen forskjell om vi velger getReference () eller finne() metode når vi sletter en eksisterende enhet.

På dette punktet lurer vi på, gjør det getReference () gjøre noen forskjell i det hele tatt da? La oss gå videre til enhetsrelasjoner og finne ut av det.

4.3. Oppdaterer enhetsrelasjoner

En annen vanlig brukssak dukker opp når vi trenger å redde forholdet mellom enhetene våre.

La oss legge til en annen metode for å demonstrere en Spiller’S deltakelse i a Spill ved å bare oppdatere Spiller‘S spill eiendom:

Spill game1 = entityManager.find (Game.class, 1L); Player player1 = entityManager.find (Player.class, 1L); player1.setGame (game1); entityManager.persist (spiller1); 

Å kjøre testen gir oss et lignende resultat en gang til og vi kan fremdeles se Å VELGE spørsmål når du bruker finne() metode:

Dvalemodus: velg game0_.id som id1_0_0_, game0_.name som name2_0_0_ fra Game game0_ hvor game0_.id =? Dvalemodus: velg spiller0_.id som id1_1_0_, spiller0_.game_id som game_id3_1_0_, player0_.name som navn2_1_0_, game1_.id som id1_0_1_, game1_.name som name2_0_1_ fra Player player0_ venstre ytre bli med Game Game1_ på player0_.game_id = game_. .id =? Dvalemodus: oppdater Player set game_id = ?, name =? hvor id =? 

La oss nå definere en test til se hvordan getReference () metoden fungerer i dette tilfellet:

Spill game2 = entityManager.getReference (Game.class, 2L); Player player1 = entityManager.find (Player.class, 1L); player1.setGame (game2); entityManager.persist (spiller1); 

Forhåpentligvis gir oss den forventede oppførselen å kjøre testen:

Dvalemodus: velg spiller0_.id som id1_1_0_, spiller0_.game_id som game_id3_1_0_, player0_.name som navn2_1_0_, game1_.id som id1_0_1_, game1_.name som name2_0_1_ fra Player player0_ venstre ytre bli med Game Game1_ på player0_.game_id = game_. .id =? Dvalemodus: oppdater Player set game_id = ?, name =? hvor id =? 

Og vi ser, Dvalemodus utfører ikke a Å VELGE spørring for Spill enhet når vi bruker getReference () denne gangen.

Så det ser ut som en god praksis å velge getReference () i dette tilfellet. Det er fordi en fullmektig Spill enhet er nok til å skape forholdet fra Spiller enhet - den Spill enhet trenger ikke å initialiseres.

Følgelig ved hjelp av getReference () kan eliminere unødvendige rundturer til databasen vår når vi oppdaterer enhetsrelasjoner.

5. Dvalemodus på første nivå

Noen ganger kan det være forvirrende begge metodene finne() og getReference () kan ikke utføre noen Å VELGE spørsmål i noen tilfeller.

La oss forestille oss en situasjon at enhetene våre allerede er lastet i utholdenhetskonteksten før vi opererte:

entityManager.getTransaction (). start (); entityManager.persist (nytt spill (1L, "spill 1")); entityManager.persist (ny spiller (1L, "spiller 1")); entityManager.getTransaction (). commit (); entityManager.getTransaction (). start (); Spill game1 = entityManager.getReference (Game.class, 1L); Player player1 = entityManager.find (Player.class, 1L); player1.setGame (game1); entityManager.persist (spiller1); entityManager.getTransaction (). commit (); 

Å kjøre testen viser at bare oppdateringsspørringen ble utført:

Dvalemodus: oppdater Player set game_id = ?, name =? hvor id =? 

I et slikt tilfelle bør vi legge merke til det vi ser ingen Å VELGE spørsmål, om vi bruker finne() eller getReference (). Dette er fordi enhetene våre er bufret i Hibernates hurtigbuffer på første nivå.

Som et resultat, når enhetene våre er lagret i dvalemodus på første nivå, så begge deler finne() og getReference () metoder virker identiske og ikke treffer databasen vår.

6. Ulike JPA-implementeringer

Som en siste påminnelse, bør vi være klar over at oppførselen til getReference () metoden avhenger av den underliggende leverandøren av utholdenhet.

I henhold til JPA 2-spesifikasjonen har utholdenhetsleverandøren lov til å kaste EntityNotFoundException når getReference () metoden kalles. Dermed kan det være annerledes for andre utholdenhetsleverandører, og vi kan støte på EntityNotFoundException når vi bruker getReference ().

Likevel, Dvalemodus følger ikke spesifikasjonen for getReference () som standard for å lagre en database tur / retur når det er mulig. Følgelig kaster det ikke noe unntak når vi henter enhetsfullmakter, selv om de ikke finnes i databasen.

Alternativt Hibernate tilbyr en konfigurasjonsegenskap for å tilby en meningsfull måte for de som ønsker å følge JPA-spesifikasjonen.

I et slikt tilfelle kan vi vurdere å sette hibernate.jpa.compliance.proxy eiendom til ekte:

Med denne innstillingen initialiserer dvalemodus uansett enhetsproxyen, noe som betyr at den utfører en Å VELGE spørring selv når vi bruker getReference ().

7. Konklusjon

I denne opplæringen undersøkte vi noen brukstilfeller som kan ha nytte av referanse-proxy-objektene og lærte hvordan du bruker EntityManager‘S getReference () metode i dvalemodus.

Som alltid er alle kodeeksemplene og flere testtilfeller for denne opplæringen tilgjengelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found