Graf entity JPA

1. Prehľad

JPA 2.1 zaviedlo funkciu Entity Graph ako sofistikovanejšiu metódu riešenia zaťaženia výkonu.

Umožňuje definovať šablónu zoskupením súvisiacich polí perzistencie, ktoré chceme načítať, a umožňuje nám zvoliť typ grafu za behu.

V tejto príručke podrobnejšie vysvetlíme, ako vytvoriť a používať túto funkciu.

2. Čo sa snaží vyriešiť graf entity

Do zavedenia JPA 2.0 sme na načítanie priradenia entít zvyčajne používali FetchType.LENIVÝ a FetchType.EAGER ako stratégie načítania. Toto dáva pokyn poskytovateľovi JPA, aby dodatočne načítal príslušné priradenie alebo nie. Táto meta konfigurácia je bohužiaľ statická a neumožňuje prepínanie medzi týmito dvoma stratégiami za behu.

Hlavným cieľom grafu entít JPA je potom zlepšenie výkonu za behu pri načítaní súvisiacich asociácií a základných polí entity.

Stručne povedané, poskytovateľ JPA načíta celý graf do jedného výberového dotazu a potom sa vyhne načítaniu asociácie s ďalšími dotazmi SELECT. Toto sa považuje za dobrý prístup k zlepšeniu výkonu aplikácií.

3. Definovanie modelu

Predtým, ako začneme skúmať graf entít, musíme definovať entity modelu, s ktorými pracujeme. Povedzme, že chceme vytvoriť blogovú stránku, na ktorej môžu používatelia komentovať a zdieľať príspevky.

Takže najskôr si dáme Používateľ subjekt:

@Entity verejná trieda Používateľ {@Id @GeneratedValue (strategy = GenerationType.IDENTITY) private Long id; súkromné ​​meno reťazca; súkromný reťazcový e-mail; // ...}

Používateľ môže zdieľať rôzne príspevky, takže potrebujeme aj Príspevok subjekt:

@Entity verejná trieda Príspevok {@Id @GeneratedValue (strategy = GenerationType.IDENTITY) súkromné ​​Dlhé id; súkromný predmet String; @OneToMany (mappedBy = "príspevok") súkromné ​​komentáre v zozname = nový ArrayList (); @ManyToOne (fetch = FetchType.LAZY) @JoinColumn súkromný používateľ; // ...}

Používateľ môže tiež komentovať zdieľané príspevky, takže na záver pridáme a Komentovať subjekt:

@Entity verejná trieda Komentár {@Id @GeneratedValue (strategy = GenerationType.IDENTITY) private Long id; súkromná reťazcová odpoveď; @ManyToOne (fetch = FetchType.LAZY) @JoinColumn súkromný príspevok do príspevku; @ManyToOne (fetch = FetchType.LAZY) @JoinColumn súkromný používateľ; // ...}

Ako vidíme, Príspevok subjekt je združený s Komentovať a Používateľ subjekty. The Komentovať subjekt má združenie k Príspevok a Používateľ subjekty.

Cieľom je potom rôznymi spôsobmi načítať nasledujúci graf:

Príspevok -> používateľ: Používateľ -> komentáre: Zobraziť komentáre [0]: Komentár -> používateľ: Komentáre používateľov [1]: Komentár -> používateľ: Používateľ

4. Načítanie príbuzných entít pomocou FetchType Stratégie

The FetchType metóda definuje dve stratégie pre načítanie údajov z databázy:

  • FetchType.EAGER: Poskytovateľ perzistencie musí načítať príslušné anotované pole alebo vlastnosť. Toto je predvolené správanie pre @Basic, @ManyToOnea @Jeden na jedného komentované polia.
  • FetchType.LAZY: Poskytovateľ vytrvalosti by mal načítať údaje pri prvom prístupe, ale dá sa načítať dychtivo. Toto je predvolené správanie pre @OneToMany, @ManyToMany a @ ElementCollection-komentované polia.

Napríklad, keď načítame a Príspevok súvisiaci subjekt Komentovať entity sa nenačítajú ako predvolené FetchType odkedy @OneToMany je LENIVÝ. Toto správanie môžeme prepísať zmenou FetchType do EAGER:

@OneToMany (mappedBy = "príspevok", fetch = FetchType.EAGER) súkromné ​​zoznamy komentárov = nový ArrayList ();

Pre porovnanie, keď načítame a Komentovať subjekt, jeho Príspevok rodičovská entita je načítaná ako predvolený režim pre @ManyToOne, ktorý je EAGER. Môžeme sa tiež rozhodnúť, že súbor nenačítame Príspevok entita zmenou tejto anotácie na LENIVÝ:

@ManyToOne (fetch = FetchType.LAZY) @JoinColumn (name = "post_id") súkromný príspevok na príspevok;

Všimnite si, že ako LENIVÝ nie je požiadavka, poskytovateľ vytrvalosti môže stále načítať Príspevok subjekt dychtivo, ak chce. Pre správne použitie tejto stratégie by sme sa teda mali vrátiť k oficiálnej dokumentácii príslušného poskytovateľa perzistencie.

Pretože sme teraz použili anotácie na opísanie našej stratégie načítania, naša definícia je statická a neexistuje spôsob, ako prepínať medzi LENIVÝ a EAGER za behu.

Tu vstupuje do hry Entity Graph, ako uvidíme v nasledujúcej časti.

5. Definovanie grafu entity

Na definovanie grafu entít môžeme buď použiť anotácie na entite, alebo môžeme programovo pokračovať pomocou API JPA.

5.1. Definovanie grafu entity s anotáciami

@NamedEntityGraph anotácia umožňuje špecifikovať atribúty, ktoré sa majú zahrnúť, keď chceme načítať entitu a súvisiace asociácie.

Najprv teda definujeme graf entít, ktorý načíta Príspevok a jeho príbuzných subjektov Používateľ a Komentovaťs:

@NamedEntityGraph (name = "post-entity-graph", attributeNodes = {@NamedAttributeNode ("subject"), @NamedAttributeNode ("user"), @NamedAttributeNode ("comments"),}) @Entity verejná trieda Príspevok {@OneToMany (mappedBy = "príspevok") komentáre súkromného zoznamu = nový ArrayList (); // ...}

V tomto príklade sme použili @NamedAttributeNode definovať súvisiace entity, ktoré sa majú načítať pri načítaní koreňovej entity.

Poďme si teraz definovať komplikovanejší Entity Graph, kde chceme načítať aj Používateľsúvisiace s Komentovaťs.

Na tento účel použijeme @NamedAttributeNode atribút podgraf. To umožňuje odkazovať na pomenovaný podgraf definovaný prostredníctvom @NamedSubgraph anotácia:

@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 verejná trieda Príspevok {@OneToMany (mappedBy =" post " ) komentáre súkromného zoznamu = nový ArrayList (); // ...}

Vymedzenie pojmu @NamedSubgraph anotácia je podobná znaku @NamedEntityGraph a umožňuje špecifikovať atribúty súvisiaceho združenia. Ak tak urobíme, môžeme zostaviť kompletný graf.

Vo vyššie uvedenom príklade s definovaným „post-entity-graph-with-comment-users ' graf, môžeme načítať Príspevok, súvisiace Užívateľ, the Pripomienky a Používateľsúvisiace s Pripomienky.

Na záver upozorňujeme, že môžeme alternatívne pridať definíciu grafu entít pomocou znaku orm.xml deskriptor nasadenia:

  ...     ... 

5.2. Definovanie grafu entít pomocou rozhrania JPA API

Entitný graf môžeme definovať aj cez EntityManager API volaním createEntityGraph () metóda:

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

Na určenie atribútov koreňovej entity používame addAttributeNodes () metóda.

entityGraph.addAttributeNodes ("predmet"); entityGraph.addAttributeNodes ("užívateľ");

Podobne na zahrnutie atribútov od súvisiacej entity používame addSubgraph () zostaviť vložený graf entít a potom my addAttributeNodes () ako sme to urobili vyššie.

entityGraph.addSubgraph ("komentáre") .addAttributeNodes ("užívateľ");

Teraz, keď sme videli, ako vytvoriť graf entít, preskúmame, ako ho použiť v nasledujúcej časti.

6. Používanie grafu entít

6.1. Typy grafov entít

JPA definuje dve vlastnosti alebo rady, podľa ktorých si môže poskytovateľ perzistencie zvoliť, aby mohol načítať alebo načítať graf entít za behu:

  • javax.persistence.fetchgraph - Z databázy sa načítajú iba zadané atribúty. Pretože v tomto výučbe používame režim dlhodobého spánku, môžeme si všimnúť, že na rozdiel od špecifikácií JPA sú atribúty staticky nakonfigurované ako EAGER sú tiež načítané.
  • javax.persistence.loadgraph - Okrem zadaných atribútov sú atribúty staticky nakonfigurované ako EAGER sú tiež vyhľadané.

V obidvoch prípadoch sa vždy načíta primárny kľúč a verzia, ak existuje.

6.2. Načítava sa graf entity

Graf entít môžeme získať rôznymi spôsobmi.

Začnime použitím EntityManager.find() metóda. Ako sme si už ukázali, predvolený režim je založený na statických meta-stratégiách FetchType.EAGER a FetchType.LAZY.

Poďme sa teda odvolať na Nájsť() a skontrolujte protokol:

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

Tu je protokol poskytnutý implementáciou režimu dlhodobého spánku:

vyberte post0_.id ako id1_1_0_, post0_.subject ako predmet2_1_0_, post0_.user_id ako user_id3_1_0_ z príspevku post0_ kde post0_.id =?

Ako vidíme z protokolu, Používateľ a Komentovať entity sa nenačítajú.

Toto predvolené správanie môžeme prepísať vyvolaním preťaženého Nájsť() metóda, ktorá prijíma rady ako a Mapa. Môžeme potom uveďte typ grafu, ktorý chceme načítať:

EntityGraph entityGraph = entityManager.getEntityGraph ("post-entity-graph"); Vlastnosti mapy = nový HashMap (); properties.put ("javax.persistence.fetchgraph", entityGraph); Post post = entityManager.find (Post.class, id, vlastnosti);

Ak sa pozrieme znova do protokolu, môžeme vidieť, že tieto entity sú teraz načítané a iba v jednom výberovom dotaze:

vyberte post0_.id ako id1_1_0_, post0_.subject ako predmet2_1_0_, post0_.user_id ako user_id3_1_0_, komentáre1_.post_id ako post_id3_0_1_, komentáre1_.id ako id1_0_1_, komentáre1_.id ako id1_0_2_, komentáre__1, post_id1 .user_id ako user_id4_0_2_, user2_.id ako id1_2_3_, user2_.email ako email2_2_3_, user2_.name ako name3_2_3_ z príspevku post0_ ľavé vonkajšie pripojenie Komentáre comments1_ k príspevku0_.id = comments1_.post_id ľavé vonkajšie pripojenie Používateľ user2_ na príspevku0_.user_id = user2_. id kde post0_.id =?

Pozrime sa, ako môžeme pomocou JPQL dosiahnuť to isté:

EntityGraph entityGraph = entityManager.getEntityGraph ("post-entity-graph-with-comment-users"); Príspevok post = entityManager.createQuery ("vyberte p z príspevku p, kde p.id =: id", Post.class) .setParameter ("id", id) .setHint ("javax.persistence.fetchgraph", entityGraph) .getSingleResult ();

A nakoniec sa pozrime na a Kritériá Príklad API:

EntityGraph entityGraph = entityManager.getEntityGraph ("post-entity-graph-with-comment-users"); CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder (); CriteriaQuery kritériáQuery = kritériaBuilder.createQuery (Post.class); Root root = criteriaQuery.from (Post.class); riteriaQuery.where (criteriaBuilder.equal (root.get ("id"), id)); TypedQuery typedQuery = entityManager.createQuery (kritériaQuery); typedQuery.setHint ("javax.persistence.loadgraph", entityGraph); Príspevok post = typedQuery.getSingleResult ();

V každej z nich typ grafu je uvedený ako pomôcka. Zatiaľ čo v prvom príklade sme použili Mapa, v dvoch neskorších príkladoch sme použili setHint () metóda.

7. Záver

V tomto článku sme skúmali použitie grafu entít JPA na dynamické načítanie súboru Subjekt a jeho združenia.

Rozhodnutie sa robí za behu, v ktorom sa rozhodneme načítať alebo nie súvisiace priradenie.

Výkon je samozrejme kľúčovým faktorom, ktorý treba brať do úvahy pri navrhovaní subjektov JPA. Dokumentácia JPA odporúča používať FetchType.LAZY stratégia vždy, keď je to možné, a graf entít, keď potrebujeme načítať priradenie.

Ako obvykle je všetok kód k dispozícii na GitHub.


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