Vzťah mnoho-veľa v JPA

1. Úvod

V tomto tutoriáli uvidíme niekoľko spôsobov, ako riešiť vzťahy medzi mnohými pomocou protokolu JPA.

Na predstavenie myšlienok použijeme model študentov, kurzy a rôzne vzťahy medzi nimi.

Kvôli jednoduchosti si v príkladoch kódu ukážeme iba atribúty a konfiguráciu JPA, ktoré súvisia so vzťahmi typu mnoho proti mnohým.

2. Základné mnoho-k-veľa

2.1. Modelovanie vzťahu medzi mnohými

Vzťah je spojenie medzi dvoma typmi entít. V prípade vzťahu medzi mnohými môžu obe strany súvisieť s viacerými prípadmi druhej strany.

Upozorňujeme, že je možné, že typy entít môžu byť vo vzájomnom vzťahu. Napríklad, keď modelujeme rodokmene: každý uzol je osoba, takže ak hovoríme o vzťahu rodiča a dieťaťa, obaja účastníci budú osobou.

Nerobí to však taký rozdiel, či hovoríme o vzťahu medzi jedným alebo viacerými typmi entít. Pretože je ľahšie premýšľať o vzťahoch medzi dvoma rôznymi typmi entít, použijeme to na ilustráciu našich prípadov.

Napríklad, keď študenti označia kurzy, ktoré sa im páčia: študent môže mať rád veľa kurzy a veľa študentom sa môže páčiť rovnaký kurz:

Ako vieme, v RDBMSes môžeme vytvárať vzťahy s cudzími kľúčmi. Pretože obe strany by mali mať možnosť odkazovať sa na druhú stranu, musíme vytvoriť samostatnú tabuľku na uchovanie cudzích kľúčov:

Takáto tabuľka sa nazýva a pripojiť sa k stolu. Upozorňujeme, že v spojovacej tabuľke bude kombinácia cudzích kľúčov jeho zloženým primárnym kľúčom.

2.2. Implementácia v JPA

Modelovanie vzťahu mnohých k mnohým s POJO je ľahké. Mali by sme zahrnúť a Zbierka v obidvoch triedach, ktorý obsahuje prvky ostatných.

Potom musíme triedu označiť @Entitya primárny kľúč s @Id aby sa z nich stali správne subjekty JPA.

Mali by sme tiež nakonfigurovať typ vzťahu. Preto zbierky označujeme @ManyToMany anotácie:

@Entity class Student {@Id Long id; @ManyToMany Sada páčiloCourses; // ďalšie vlastnosti // štandardné konštruktory, getre a settery} @Entity class Course {@Id Long id; @ManyToMany Nastaviť lajky; // ďalšie vlastnosti // štandardné konštruktory, getre a setre}

Ďalej musíme nakonfigurovať, ako modelovať vzťah v RDBMS.

Na strane vlastníka konfigurujeme vzťah, ktorý pre tento príklad vyberieme Študent trieda.

Môžeme to urobiť pomocou @JoinTable anotácia v Študent trieda. Poskytujeme názov tabuľky spojenia (samozrejme_podobne) a cudzie kľúče s @JoinColumn anotácie. The joinColumn atribút sa pripojí k strane vlastníka vzťahu a inverseJoinColumn na druhú stranu:

@ManyToMany @JoinTable (name = "course_like", joinColumns = @JoinColumn (name = "student_id"), inverseJoinColumns = @JoinColumn (name = "course_id")) Nastaviť páčené kurzy;

Všimnite si, že pomocou @JoinTable, alebo dokonca @JoinColumn nie je povinné: JPA pre nás vygeneruje názvy tabuliek a stĺpcov. Stratégia, ktorú používa JPA, sa však nemusí vždy zhodovať s konvenciami pomenovania, ktoré používame. Preto možnosť konfigurovať názvy tabuliek a stĺpcov.

Na cieľovej strane musíme uviesť iba názov poľa, ktoré mapuje vzťah. Preto sme nastavili mappedBy atribút @ManyToMany anotácia v Samozrejme trieda:

@ManyToMany (mappedBy = "likesCourses") Nastaviť lajky;

Všimnite si, že od vzťah mnoho proti mnohým nemá v databáze stranu vlastníka, mohli by sme nakonfigurovať tabuľku spojení v Samozrejme triedy a odkázať na ňu z Študent trieda.

3. Mnoho na veľa pomocou zloženého kľúča

3.1. Modelovanie atribútov vzťahov

Povedzme, že chceme nechať študentov hodnotiť kurzy. Študent môže hodnotiť ľubovoľný počet kurzov a ľubovoľný počet študentov môže hodnotiť rovnaký kurz. Preto je to tiež vzťah medzi mnohými. O niečo je to komplikovanejšie hodnotiaci vzťah sa netýka iba skutočnosti, že existuje. Musíme si uložiť hodnotiace skóre, ktoré študent v kurze dal.

Kde môžeme tieto informácie uložiť? Nemôžeme to vložiť do Študent študent môže dať rôznym kurzom rôzne hodnotenie. Podobne, jeho uloženie do Samozrejme subjekt by tiež nebol dobrým riešením.

Toto je situácia, keď samotný vzťah má prívlastok.

Pomocou tohto príkladu pripojenie atribútu k relácii vyzerá v ER diagrame takto:

Môžeme to modelovať takmer rovnako, ako sme to robili s jednoduchým vzťahom typu mnoho-veľa. Jediný rozdiel je v tom, že k tabuľke spojenia pripájame nový atribút:

3.2. Vytvorenie zloženého kľúča v JPA

Implementácia jednoduchého vzťahu medzi mnohými bola dosť jednoduchá. Jediným problémom je, že takto nemôžeme do vzťahu pridať nehnuteľnosť, pretože sme entity prepojili priamo. Preto nemali sme ako pridať vlastnosť do samotného vzťahu.

Pretože mapujeme atribúty DB na polia triedy v JPA, musíme pre vzťah vytvoriť novú triedu entít.

Každá entita JPA samozrejme potrebuje primárny kľúč. Pretože náš primárny kľúč je zložený kľúč, musíme vytvoriť novú triedu, ktorá bude obsahovať rôzne časti kľúča:

@Embeddable trieda CourseRatingKey implementuje Serializable {@Column (name = "student_id") Long studentId; @Column (name = "course_id") Dlhý identifikátor kurzu; // štandardné konštruktory, getre a nastavovače // hashcode a rovná sa implementácia}

Všimnite si, že nejaké sú kľúčové požiadavky, ktoré musí trieda zložených kľúčov spĺňať:

  • Musíme to označiť @Embeddable
  • Musí sa to zaviesť java.io. Serializovateľné
  • Musíme zabezpečiť implementáciu hashcode () a rovná sa () metódy
  • Žiadne z polí nemôže byť samotnou entitou

3.3. Používanie zloženého kľúča v JPA

Pomocou tejto triedy zložených kľúčov môžeme vytvoriť triedu entít, ktorá modeluje spojovaciu tabuľku:

@Entity class CourseRating {@EmbeddedId CourseRatingKey id; @ManyToOne @MapsId ("studentId") @JoinColumn (name = "student_id") Študent; @ManyToOne @MapsId ("courseId") @JoinColumn (name = "course_id") Kurz kurzu; hodnotenie int; // štandardné konštruktory, getre a setre}

Tento kód je veľmi podobný bežnej implementácii entity. Máme však niektoré kľúčové rozdiely:

  • použili sme @EmbeddedId, na označenie primárneho kľúča, ktorý je inštanciou CourseRatingKey trieda
  • označili sme študent a samozrejme polia s @MapsId

@MapsId Znamená to, že tieto polia spojíme s časťou kľúča a sú to cudzie kľúče vzťahu mnohých proti jednej. Potrebujeme to, pretože ako sme už spomenuli vyššie, v zloženom kľúči nemôžeme mať entity.

Potom môžeme nakonfigurovať inverzné odkazy v Študent a Samozrejme subjekty ako predtým:

trieda Študent {// ... @OneToMany (mappedBy = "student") Nastaviť hodnotenie; // ...} kurz triedy {// ... @OneToMany (mappedBy = "course") Nastaviť hodnotenie; // ...}

Upozorňujeme, že existuje alternatívny spôsob použitia zložených kľúčov: @IdClass anotácia.

3.4. Ďalšie charakteristiky

Nakonfigurovali sme vzťahy na Študent a Samozrejme triedy ako @ManyToOne. Mohli by sme to urobiť, pretože s novou entitou sme štruktúrne rozložili vzťah mnoho proti mnohým na dva vzťahy mnoho proti jednej.

Prečo sme to dokázali? Ak si pozorne prezrieme tabuľky v predchádzajúcom prípade, vidíme, že obsahovala dva vzťahy typu „jedna k jednej“. Inými slovami, v RDBMS nie je žiadny vzťah medzi mnohými. Štruktúry, ktoré vytvárame spojovacími tabuľkami, nazývame vzťahy medzi mnohými, pretože to modelujeme.

Okrem toho je jasnejšie, keď hovoríme o vzťahoch medzi mnohými, pretože to je náš zámer. Medzitým je tabuľka spojení iba implementačným detailom; nás to vlastne nezaujíma.

Toto riešenie má navyše ďalšiu funkciu, ktorú sme ešte nespomenuli. Jednoduché riešenie typu multi-to-many vytvára vzťah medzi dvoma entitami. Preto nemôžeme rozšíriť vzťah na viac entít. V tomto riešení však nemáme tento limit: môžeme modelovať vzťahy medzi ľubovoľným počtom typov entít.

Napríklad keď môže kurz učiť viac učiteľov, môžu študenti ohodnotiť, ako konkrétny učiteľ učí konkrétny kurz. Týmto spôsobom by hodnotenie predstavovalo vzťah medzi tromi entitami: študentom, kurzom a učiteľom.

4. Mnoho ľudí s novým subjektom

4.1. Modelovanie atribútov vzťahov

Povedzme, že chceme umožniť študentom prihlásiť sa na kurzy. Tiež musíme uložiť bod, keď sa študent prihlásil na konkrétny kurz. Okrem toho si tiež chceme uložiť, akú známku v kurze získala.

V ideálnom svete by sme to mohli vyriešiť predchádzajúcim riešením, keď sme mali entitu so zloženým kľúčom. Náš svet však nie je ani zďaleka ideálny a študenti nie vždy absolvujú kurz na prvý pokus.

V tomto prípade existujú viacnásobné prepojenie medzi rovnakými pármi študentov a kurzovalebo viac riadkov s rovnakými id_udca_kurzu páry. Nemôžeme ho modelovať pomocou žiadneho z predchádzajúcich riešení, pretože všetky primárne kľúče musia byť jedinečné. Preto musíme použiť samostatný primárny kľúč.

Preto môžeme predstaviť entitu, ktorá bude obsahovať atribúty registrácie:

V tomto prípade, registračná entita predstavuje vzťah medzi ostatnými dvoma subjektmi.

Pretože je to entita, bude mať svoj vlastný primárny kľúč.

Upozorňujeme, že v predchádzajúcom riešení sme mali zložený primárny kľúč, ktorý sme vytvorili z dvoch cudzích kľúčov. Dva cudzie kľúče teraz nebudú súčasťou primárneho kľúča:

4.2. Implementácia v JPA

Keďže coure_registration stal obyčajnou tabuľkou, môžeme vytvoriť obyčajnú starú entitu JPA, ktorá ju modeluje:

@Entity class CourseRegistration {@Id Long id; @ManyToOne @JoinColumn (name = "id_študenta") Študent; @ManyToOne @JoinColumn (name = "course_id") Kurz kurzu; LocalDateTime registeredAt; int stupeň; // ďalšie vlastnosti // štandardné konštruktory, getre a setre}

Musíme tiež nakonfigurovať vzťahy v Študent a Samozrejme triedy:

trieda Študent {// ... @OneToMany (mappedBy = "student") Nastaviť registrácie; // ...} kurz triedy {// ... @OneToMany (mappedBy = "courses") Nastaviť registrácie; // ...}

Znovu sme nakonfigurovali vzťah skôr. Zostáva nám teda iba povedať spoločnosti JPA, kde nájde túto konfiguráciu.

Toto riešenie by sme mohli použiť na riešenie predchádzajúceho problému: kurzov hodnotenia študentov. Je však čudné vytvárať vyhradený primárny kľúč, pokiaľ to nemusíme. Z pohľadu RDBMS to navyše nedáva veľký zmysel, pretože kombináciou dvoch cudzích kľúčov vznikol perfektný zložený kľúč. Okrem toho zložený kľúč mal jasný význam: ktoré entity spájame vo vzťahu.

V opačnom prípade je výber medzi týmito dvoma implementáciami často jednoducho osobnou preferenciou.

5. Záver

V tomto tutoriáli sme videli, čo je to vzťah medzi mnohými a ako ho môžeme modelovať v RDBMS pomocou JPA.

Videli sme tri spôsoby, ako to modelovať v JPA. Všetky tri majú odlišné výhody a nevýhody, pokiaľ ide o:

  • jasnosť kódu
  • Jasnosť DB
  • schopnosť priradiť atribúty vzťahu
  • koľko subjektov môžeme prepojiť so vzťahom a
  • podpora viacerých spojení medzi rovnakými entitami

Ako obvykle sú príklady k dispozícii na GitHub.


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