Mange-til-mange-forhold i JPA

1. Introduktion

I denne vejledning ser vi flere måder at håndtere mange-til-mange relationer ved hjælp af JPA.

For at præsentere idéerne bruger vi en model af studerende, kurser og forskellige forhold mellem dem.

For enkelheds skyld viser vi i kodeeksemplerne kun attributterne og JPA-konfigurationen, der er relateret til de mange-til-mange-forhold.

2. Grundlæggende mange-for-mange

2.1. Modellering af et forhold mellem mange og mange

Et forhold er en forbindelse mellem to typer enheder. I tilfælde af et mange-til-mange forhold kan begge sider forholde sig til flere forekomster af den anden side.

Bemærk, at det er muligt for enhedstyper at være i et forhold til sig selv. For eksempel når vi modellerer slægtstræer: hver knude er en person, så hvis vi taler om forholdet mellem forælder og barn, vil begge deltagere være en person.

Det gør dog ikke sådan en forskel, om vi taler om et forhold mellem enkelt eller flere enhedstyper. Da det er lettere at tænke på forholdet mellem to forskellige enhedstyper, bruger vi det til at illustrere vores sager.

For eksempel når de studerende markerer de kurser, de kan lide: en studerende kan lide mange kurser og mange studerende kan lide det samme kursus:

Som vi ved, kan vi i RDBMSes skabe relationer med udenlandske nøgler. Da begge sider skal kunne henvise til den anden, vi er nødt til at oprette en separat tabel, der indeholder de fremmede nøgler:

En sådan tabel kaldes a slutte sig til bordet. Bemærk, at i en sammenføjningstabel vil kombinationen af ​​de fremmede nøgler være dens sammensatte primære nøgle.

2.2. Implementering i JPA

Modellering af et mange-til-mange forhold til POJO'er det er nemt. Vi skulle inkluderer en Kollektion i begge klasser, som indeholder de andres elementer.

Derefter skal vi markere klassen med @Enhed, og den primære nøgle med @Id for at gøre dem til rigtige JPA-enheder.

Vi skal også konfigurere forholdstypen. Derfor vi markerer samlingerne med @ManyToMany kommentarer:

@Entity class Student {@Id Lang id; @ManyToMany Set kunne lideCourses; // yderligere egenskaber // standardkonstruktører, getters og setter} @Entity class Course {@Id Long id; @ManyToMany Sæt lide; // yderligere egenskaber // standardkonstruktører, getters og setter}

Derudover skal vi konfigurere, hvordan vi skal modellere forholdet i RDBMS.

Ejersiden er, hvor vi konfigurerer forholdet, som vi i dette eksempel vælger Studerende klasse.

Vi kan gøre dette med @JoinTable kommentar i Studerende klasse. Vi angiver navnet på tilslutningstabellen (kursuslignende), og de fremmede nøgler med @JoinColumn kommentarer. Det joinColumn attribut opretter forbindelse til ejersiden af ​​forholdet og inverseJoinColumn til den anden side:

@ManyToMany @JoinTable (name = "course_like", joinColumns = @JoinColumn (name = "student_id"), inverseJoinColumns = @JoinColumn (name = "course_id")) Set likedCourses;

Bemærk, at brug af @JoinTable, eller endda @JoinColumn er ikke påkrævet: JPA genererer tabel- og kolonnenavnene for os. Imidlertid matcher den strategi, som JPA bruger, ikke altid de navngivningskonventioner, vi bruger. Derfor muligheden for at konfigurere tabel- og kolonnenavne.

På målsiden skal vi kun angive navnet på det felt, der kortlægger forholdet. Derfor indstiller vi kortlagt af attribut for @ManyToMany kommentar i Rute klasse:

@ManyToMany (mappedBy = "likedCourses") Angiv likes;

Bemærk, at siden et forhold mellem mange og mange har ikke en ejerside i databasen, kunne vi konfigurere sammenføjningstabellen i Rute klasse og henvise til den fra Studerende klasse.

3. Mange-til-mange ved hjælp af en sammensat nøgle

3.1. Modelleringsforholdsattributter

Lad os sige, at vi vil lade studerende bedømme kurserne. En studerende kan bedømme et vilkårligt antal kurser, og et hvilket som helst antal studerende kan bedømme det samme kursus. Derfor er det også et mange-til-mange forhold. Hvad gør det lidt mere kompliceret er det der er mere i vurderingsforholdet end det faktum, at det eksisterer. Vi er nødt til at gemme den klassificering, som den studerende gav på kurset.

Hvor kan vi gemme disse oplysninger? Vi kan ikke sætte det i Studerende enhed, da en studerende kan give forskellige vurderinger til forskellige kurser. Tilsvarende opbevarer den i Rute enhed ville heller ikke være en god løsning.

Dette er en situation, hvornår forholdet selv har en attribut.

Ved hjælp af dette eksempel ser tilknytning af en attribut til en relation sådan ud i et ER-diagram:

Vi kan modellere det næsten på samme måde som vi gjorde med det enkle mange-til-mange forhold. Den eneste forskel er, at vi vedhæfter en ny attribut til tilslutningstabellen:

3.2. Oprettelse af en sammensat nøgle i JPA

Implementeringen af ​​et simpelt forhold mellem mange og mange var ret ligetil. Det eneste problem er, at vi ikke kan føje en egenskab til et forhold på den måde, fordi vi forbandt enhederne direkte. Derfor, vi havde ingen måde at tilføje en egenskab til selve forholdet.

Da vi kortlægger DB-attributter til klassefelter i JPA, vi er nødt til at oprette en ny enhedsklasse til forholdet.

Naturligvis har hver JPA-enhed brug for en primær nøgle. Da vores primære nøgle er en sammensat nøgle, skal vi oprette en ny klasse, der indeholder de forskellige dele af nøglen:

@Embeddable class CourseRatingKey implementerer Serializable {@Column (name = "student_id") Lang studentId; @Column (name = "course_id") Lang kursus-id; // standardkonstruktører, getters og setter // hashcode og svarer til implementering}

Bemærk, at der er nogle nøglekrav, som en sammensat nøgleklasse skal opfylde:

  • Vi er nødt til at markere det med @Embeddable
  • Det skal implementeres java.io.Serialiserbar
  • Vi er nødt til at give en implementering af hashcode () og lige med() metoder
  • Ingen af ​​felterne kan være en enhed selv

3.3. Brug af en sammensat nøgle i JPA

Ved hjælp af denne sammensatte nøgleklasse kan vi oprette enhedsklassen, som modellerer sammenføjningstabellen:

@Entity class CourseRating {@EmbeddedId CourseRatingKey id; @ManyToOne @MapsId ("studentId") @JoinColumn (name = "student_id") Studerende; @ManyToOne @MapsId ("courseId") @JoinColumn (name = "course_id") Kursuskursus; int-vurdering; // standardkonstruktører, getters og settere}

Denne kode svarer meget til en almindelig implementering af enheder. Vi har dog nogle vigtige forskelle:

  • vi brugte @EmbeddedId, for at markere den primære nøgle, som er en forekomst af CourseRatingKey klasse
  • vi markerede studerende og Rute felter med @MapsId

@MapsId betyder, at vi binder disse felter til en del af nøglen, og de er de fremmede nøgler i et mange-til-et forhold. Vi har brug for det, for som vi nævnte ovenfor, i den sammensatte nøgle kan vi ikke have enheder.

Efter dette kan vi konfigurere de inverse referencer i Studerende og Rute enheder som før:

class Student {// ... @OneToMany (mappedBy = "student") Angiv karakterer; // ...} klasse Kursus {// ... @OneToMany (mappedBy = "kursus") Angiv karakterer; // ...}

Bemærk, at der er en alternativ måde at bruge sammensatte taster på: @IdClass kommentar.

3.4. Yderligere egenskaber

Vi konfigurerede forholdet til Studerende og Rute klasser som @ManyToOne. Vi kunne gøre dette, for med den nye enhed nedbrudte vi strukturelt mange-til-mange-forholdet til to mange-til-en-forhold.

Hvorfor kunne vi gøre dette? Hvis vi inspicerer tabellerne nøje i det foregående tilfælde, kan vi se, at den indeholdt to mange-til-en-forhold. Med andre ord er der ikke noget mange-til-mange forhold i en RDBMS. Vi kalder de strukturer, vi opretter med join-tabeller, mange-til-mange-relationer, fordi det er det, vi modellerer.

Desuden er det mere klart, hvis vi taler om mange-til-mange forhold, fordi det er vores hensigt. I mellemtiden er en tilslutningstabel kun en implementeringsdetalje; vi er ligeglad med det.

Desuden har denne løsning en ekstra funktion, som vi ikke nævnte endnu. Den enkle mange-til-mange-løsning skaber et forhold mellem to enheder. Derfor kan vi ikke udvide forholdet til flere enheder. Men i denne løsning har vi ikke denne grænse: vi kan modellere forhold mellem et hvilket som helst antal enhedstyper.

For eksempel, når flere lærere kan undervise i et kursus, kan eleverne bedømme, hvordan en bestemt lærer underviser i et bestemt kursus. På den måde ville en vurdering være et forhold mellem tre enheder: en studerende, et kursus og en lærer.

4. Mange-til-mange med en ny enhed

4.1. Modelleringsforholdsattributter

Lad os sige, at vi vil lade studerende tilmelde sig kurser. Også, vi er nødt til at gemme det punkt, hvor en studerende tilmeldte sig et specifikt kursus. Oven i købet vil vi også gemme, hvilken karakter hun fik på kurset.

I en ideel verden kunne vi løse dette med den tidligere løsning, da vi havde en enhed med en sammensat nøgle. Vores verden er dog langt fra ideel, og studerende gennemfører ikke altid et kursus ved første forsøg.

I dette tilfælde er der flere forbindelser mellem de samme studerendes kursuspareller flere rækker med det samme student_id-kursus_id par. Vi kan ikke modellere det ved hjælp af nogen af ​​de tidligere løsninger, fordi alle primære nøgler skal være unikke. Derfor er vi nødt til at bruge en separat primærnøgle.

Derfor, vi kan introducere en enhed, som vil indeholde attributterne for registreringen:

I dette tilfælde, Registreringsenheden repræsenterer forholdet mellem de to andre enheder.

Da det er en enhed, har den sin egen primære nøgle.

Bemærk, at vi i den tidligere løsning havde en sammensat primærnøgle, som vi oprettede ud fra de to fremmede nøgler. Nu er de to fremmednøgler ikke den del af den primære nøgle:

4.2. Implementering i JPA

Siden den coure_registration blev en almindelig tabel, kan vi oprette en almindelig gammel JPA-enhed, der modellerer den:

@Entity class CourseRegistration {@Id Long id; @ManyToOne @JoinColumn (name = "student_id") Studerende; @ManyToOne @JoinColumn (name = "course_id") Kursuskursus; LocalDateTime registeredAt; int klasse; // yderligere egenskaber // standardkonstruktører, getters og setter}

Vi er også nødt til at konfigurere forholdene i Studerende og Rute klasser:

klasse Elev {// ... @OneToMany (mappedBy = "student") Angiv tilmeldinger; // ...} klasse Kursus {// ... @OneToMany (mappedBy = "kurser") Angiv tilmeldinger; // ...}

Igen konfigurerede vi forholdet før. Derfor behøver vi kun fortælle JPA, hvor kan den finde den konfiguration.

Bemærk, at vi kunne bruge denne løsning til at løse det tidligere problem: studerende vurderer kurser. Det føles dog underligt at oprette en dedikeret primærnøgle, medmindre vi er nødt til det. Ud fra et RDBMS-perspektiv giver det ikke meget mening, da kombinationen af ​​de to fremmednøgler gjorde en perfekt sammensat nøgle. Udover det sammensat nøgle havde en klar betydning: hvilke enheder vi forbinder i forholdet.

Ellers er valget mellem disse to implementeringer ofte simpelthen personlig præference.

5. Konklusion

I denne vejledning så vi, hvad et mange-til-mange forhold er, og hvordan kan vi modellere det i en RDBMS ved hjælp af JPA.

Vi så tre måder at modellere det på i JPA. Alle tre har forskellige fordele og ulemper, når det gælder:

  • kode klarhed
  • DB klarhed
  • evne til at tildele attributter til forholdet
  • hvor mange enheder kan vi forbinde med forholdet, og
  • understøttelse af flere forbindelser mellem de samme enheder

Som sædvanligt er eksemplerne tilgængelige på GitHub.


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