JPA-enhedsgraf

1. Oversigt

JPA 2.1 har introduceret funktionen Enhedsgraf som en mere sofistikeret metode til håndtering af ydeevneindlæsning.

Det gør det muligt at definere en skabelon ved at gruppere de relaterede persistensfelter, som vi vil hente, og lader os vælge graftypen ved kørsel.

I denne vejledning forklarer vi mere detaljeret, hvordan du opretter og bruger denne funktion.

2. Hvad enhedsgrafen prøver at løse

Indtil JPA 2.0 brugte vi normalt for at indlæse en enhedsforening FetchType.DOVEN og FetchType.IVRIGE som hentestrategier. Dette instruerer JPA-udbyderen om yderligere at hente den relaterede tilknytning eller ej. Desværre er denne metakonfiguration statisk og tillader ikke at skifte mellem disse to strategier under kørsel.

Hovedmålet med JPA-entitetsgrafen er derefter at forbedre runtime-ydelsen, når enhedens relaterede tilknytninger og grundlæggende felter indlæses.

Kort sagt, JPA-udbyderen indlæser al grafen i en valgt forespørgsel og undgår derefter at hente tilknytning til flere SELECT-forespørgsler. Dette betragtes som en god tilgang til forbedring af applikationsydelse.

3. Definition af modellen

Før vi begynder at udforske enhedsgrafen, skal vi definere de modelenheder, vi arbejder med. Lad os sige, at vi vil oprette et blog-websted, hvor brugerne kan kommentere og dele indlæg.

Så først får vi en Bruger enhed:

@Entity offentlig klasse bruger {@Id @GeneratedValue (strategi = GenerationType.IDENTITY) privat Lang id; privat strengnavn; privat streng e-mail; // ...}

Brugeren kan dele forskellige indlæg, så vi har også brug for en Stolpe enhed:

@Entity public class Post {@Id @GeneratedValue (strategi = GenerationType.IDENTITY) privat Lang id; privat strengemne; @OneToMany (mappedBy = "post") private Listekommentarer = ny ArrayList (); @ManyToOne (fetch = FetchType.LAZY) @JoinColumn privat brugerbruger; // ...}

Brugeren kan også kommentere de delte indlæg, så endelig tilføjer vi en Kommentar enhed:

@Entity offentlig klasse Kommentar {@Id @GeneratedValue (strategi = GenerationType.IDENTITY) privat Lang id; privat streng svar; @ManyToOne (fetch = FetchType.LAZY) @JoinColumn privat indlæg; @ManyToOne (fetch = FetchType.LAZY) @JoinColumn privat brugerbruger; // ...}

Som vi kan se, er Stolpe enhed har tilknytning til Kommentar og Bruger enheder. Det Kommentar enhed har en tilknytning til Stolpe og Bruger enheder.

Målet er derefter at indlæse følgende graf på forskellige måder:

Indlæg -> bruger: Bruger -> kommentarer: Listekommentarer [0]: Kommentar -> bruger: Brugerkommentarer [1]: Kommentar -> bruger: Bruger

4. Indlæser relaterede enheder med FetchType Strategier

Det FetchType metode definerer to strategier til at hente data fra databasen:

  • FetchType.EAGER: Persistensudbyderen skal indlæse det relaterede kommenterede felt eller ejendom. Dette er standardadfærden for @Grundlæggende, @ManyToOneog @En til en kommenterede felter.
  • FetchType.LAZY: Persistensudbyderen skal indlæse data, når den først er adgang, men kan indlæses ivrig. Dette er standardadfærden for @OneToMany, @ManyToMany og @ ElementCollection-kommenterede felter.

For eksempel når vi indlæser en Stolpe enhed, den relaterede Kommentar enheder indlæses ikke som standard FetchType siden @OneToMany er DOVEN. Vi kan tilsidesætte denne adfærd ved at ændre FetchType til IVRIGE:

@OneToMany (mappedBy = "post", fetch = FetchType.EAGER) private Listekommentarer = ny ArrayList ();

Til sammenligning, når vi indlæser en Kommentar enhed, hans Stolpe overordnet enhed indlæses som standardtilstand for @ManyToOne, som er IVRIGE. Vi kan også vælge ikke at indlæse Stolpe enhed ved at ændre denne kommentar til DOVEN:

@ManyToOne (fetch = FetchType.LAZY) @JoinColumn (name = "post_id") privat indlæg;

Bemærk, at som DOVEN er ikke et krav, kan persistensudbyderen stadig indlæse Stolpe enhed ivrigt, hvis den vil. Så for at bruge denne strategi korrekt, skal vi gå tilbage til den officielle dokumentation fra den tilsvarende udholdenhedsudbyder.

Nu, fordi vi har brugt annoteringer til at beskrive vores hentningsstrategi, vores definition er statisk, og der er ingen måde at skifte mellem DOVEN og IVRIGE ved kørselstid.

Det er her, entitetsgrafen kommer i spil, som vi ser i næste afsnit.

5. Definition af en enhedsgraf

For at definere en enhedsgraf kan vi enten bruge kommentarerne på enheden, eller vi kan fortsætte programmatisk ved hjælp af JPA API.

5.1. Definition af en enhedsgraf med kommentarer

Det @NamedEntityGraph annotation gør det muligt at specificere de attributter, der skal medtages, når vi vil indlæse enheden og de relaterede tilknytninger.

Så lad os først definere en enhedsgraf, der indlæser Stolpe og hans beslægtede enheder Bruger og Kommentars:

@NamedEntityGraph (name = "post-entity-graph", attributeNodes = {@NamedAttributeNode ("subject"), @NamedAttributeNode ("user"), @NamedAttributeNode ("comments"),}) @Entity public class Post {@OneToMany (mappedBy = "post") private Listekommentarer = ny ArrayList (); // ...}

I dette eksempel har vi brugt @NamedAttributeNode for at definere de relaterede enheder, der skal indlæses, når rodenheden indlæses.

Lad os nu definere en mere kompliceret enhedsgraf, hvor vi også vil indlæse Brugerer relateret til Kommentars.

Til dette formål bruger vi @NamedAttributeNode undergrafattribut. Dette gør det muligt at henvise til en navngivet undergraf defineret gennem @NamedSubgraph kommentar:

@NamedEntityGraph (name = "post-entity-graph-with-comment-users", attributeNodes = {@NamedAttributeNode ("subject"), @NamedAttributeNode ("user"), @NamedAttributeNode (value = "comments", subgraph = " comments-subgraph "),}, subgraphs = {@NamedSubgraph (name =" comments-subgraph ", attributeNodes = {@NamedAttributeNode (" user ")}}}) @Entity public class Post {@OneToMany (mappedBy =" post " ) private listekommentarer = ny ArrayList (); // ...}

Definitionen af @NamedSubgraph kommentar svarer til @NamedEntityGraph og tillader at specificere attributter for den relaterede tilknytning. På den måde kan vi konstruere en komplet graf.

I eksemplet ovenfor med den definerede 'post-entity-graph-with-comment-users ' graf, kan vi indlæse Stolpe, det relaterede Bruger, det Kommentarer og Brugerer relateret til Kommentarer.

Endelig bemærk, at vi alternativt kan tilføje definitionen af ​​enhedsgrafen ved hjælp af orm.xml implementeringsbeskrivelse:

  ...     ... 

5.2. Definition af en enhedsgraf med JPA API

Vi kan også definere enhedsgrafen gennem EntityManager API ved at ringe til createEntityGraph () metode:

EntityGraph entityGraph = entityManager.createEntityGraph (Post.class);

For at specificere attributterne for rodenheden bruger vi addAttributeNodes () metode.

entityGraph.addAttributeNodes ("emne"); entityGraph.addAttributeNodes ("bruger");

For at inkludere attributter fra den relaterede enhed bruger vi ligeledes addSubgraph () at konstruere en indlejret enhedsgraf, og så skal vi addAttributeNodes () som vi gjorde ovenfor.

entityGraph.addSubgraph ("kommentarer") .addAttributeNodes ("bruger");

Nu hvor vi har set, hvordan man opretter enhedsgrafen, undersøger vi, hvordan man bruger den i næste afsnit.

6. Brug af enhedsgrafen

6.1. Typer af enhedsgrafer

JPA definerer to egenskaber eller tip, som vedholdenhedsudbyderen kan vælge for at indlæse eller hente enhedsgrafen ved kørsel:

  • javax.persistence.fetchgraph - Kun de specificerede attributter hentes fra databasen. Da vi bruger dvale i denne vejledning, kan vi bemærke, at attributter statisk konfigureret som i modsætning til JPA-specifikationerne IVRIGE er også indlæst.
  • javax.persistence.loadgraph - Ud over de angivne attributter er attributter statisk konfigureret som IVRIGE hentes også.

I begge tilfælde indlæses altid den primære nøgle og den eventuelle version.

6.2. Indlæsning af en enhedsgraf

Vi kan hente enhedsgrafen på forskellige måder.

Lad os starte med at bruge EntityManager.find() metode. Som vi allerede har vist, er standardtilstanden baseret på de statiske metastrategier FetchType.EAGER og FetchType.LAZY.

Så lad os påberåbe os finde() metode og inspicere loggen:

Post post = entityManager.find (Post.class, 1L);

Her er logfilen fra implementeringen af ​​dvale:

vælg post0_.id som id1_1_0_, post0_.emne som subject2_1_0_, post0_.user_id som user_id3_1_0_ fra Post post0_ hvor post0_.id =?

Som vi kan se fra logfilen, Bruger og Kommentar enheder er ikke indlæst.

Vi kan tilsidesætte denne standardadfærd ved at påkalde den overbelastede finde() metode, der accepterer tip som en Kort. Det kan vi så give den graftype, som vi vil indlæse:

EntityGraph entityGraph = entityManager.getEntityGraph ("post-entity-graph"); Kortegenskaber = nyt HashMap (); egenskaber.put ("javax.persistence.fetchgraph", entityGraph); Post post = entityManager.find (Post.class, id, egenskaber);

Hvis vi ser igen i loggen, kan vi se, at disse enheder nu er indlæst og kun i en valgt forespørgsel:

vælg post0_.id som id1_1_0_, post0_.emne som emne2_1_0_, post0_.bruger_id som bruger_id3_1_0_, kommentarer1_.post_id som post_id3_0_1_, comments1_.id som id1_0_1_, kommentarer1_.id som id1_0_2_, kommentarer1_.post_id_ som___ .bruger_id som bruger_id4_0_2_, bruger2_.id som id1_2_3_, bruger2_.email som e-mail2_2_3_, bruger2_.navn som navn3_2_3_ fra Indlæg post0_ venstre ydre sammenføjning Kommentar kommentarer1_ på post0_.id = kommentarer1_.post_id venstre ydre sammenføjning Brugerbruger2_ på post0_.user_id = bruger_. id hvor post0_.id =?

Lad os se, hvordan vi kan opnå det samme ved hjælp af JPQL:

EntityGraph entityGraph = entityManager.getEntityGraph ("post-entity-graph-with-comment-users"); Post post = entityManager.createQuery ("vælg p fra Post p hvor p.id =: id", Post.class) .setParameter ("id", id) .setHint ("javax.persistence.fetchgraph", entityGraph) .getSingleResult ();

Og endelig, lad os se på en Kriterier API-eksempel:

EntityGraph entityGraph = entityManager.getEntityGraph ("post-entity-graph-with-comment-users"); CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder (); CriteriaQuery criteriaQuery = criteriaBuilder.createQuery (Post.class); Root root = criteriaQuery.from (Post.class); criteriaQuery.where (criteriaBuilder.equal (root.get ("id"), id)); TypedQuery typedQuery = entityManager.createQuery (criteriaQuery); typedQuery.setHint ("javax.persistence.loadgraph", entityGraph); Indlæg post = typedQuery.getSingleResult ();

I hver af disse, graftypen er angivet som et tip. Mens vi i det første eksempel brugte Kort, i de to senere eksempler har vi brugt setHint () metode.

7. Konklusion

I denne artikel har vi undersøgt brugen af ​​JPA-enhedsgrafen til dynamisk at hente en Enhed og dets foreninger.

Beslutningen træffes i løbetid, hvor vi vælger at indlæse eller ikke den relaterede tilknytning.

Ydeevne er naturligvis en nøglefaktor, der skal tages i betragtning ved design af JPA-enheder. JPA-dokumentationen anbefaler, at du bruger FetchType.LAZY strategi, når det er muligt, og enhedsgrafen, når vi har brug for at indlæse en tilknytning.

Som sædvanlig er al koden tilgængelig på GitHub.


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