En-til-en-forhold i JPA
1. Introduksjon
I denne opplæringen vil vi se på forskjellige måter å lage en-til-en-tilordninger i JPA.
Vi trenger en grunnleggende forståelse av Hibernate-rammeverket, så sjekk ut vår guide til Hibernate 5 med Spring for ekstra bakgrunn.
2. Beskrivelse
La oss anta at vi bygger et brukerstyringssystem, og sjefen vår ber oss om å lagre en postadresse for hver bruker. En bruker vil ha en postadresse, og en postadresse vil bare ha en bruker knyttet til den.
Dette er et eksempel på et en-til-en forhold, i dette tilfellet mellom bruker og adresse enheter.
La oss se hvordan vi kan implementere dette i de påfølgende delene.
3. Bruke en utenlandsk nøkkel
3.1. Modellering med en utenlandsk nøkkel
La oss ta en titt på følgende ER-diagram som representerer en fremmed nøkkelbasert en-til-en-kartlegging:
I dette eksemplet er adresse_id kolonne i brukere er den utenlandske nøkkelen til adresse.
3.2. Implementering med en utenlandsk nøkkel i JPA
La oss først lage Bruker klasse og kommentere det på riktig måte:
@Entity @Table (name = "brukere") offentlig klasse bruker {@Id @GeneratedValue (strategi = GenerationType.AUTO) @Column (name = "id") privat Lang id; // ... @OneToOne (cascade = CascadeType.ALL) @JoinColumn (name = "address_id", referertColumnName = "id") privat adresse adresse; // ... getters og setters}
Noter det vi plasserer @OneToOne kommentar på det relaterte enhetsfeltet, Adresse.
Også, vi trenger å plassere @JoinColumn kommentar for å konfigurere navnet på kolonnen i brukere tabell som tilordnes til hovednøkkelen i adresse bord. Hvis vi ikke oppgir noe navn, vil dvalemodus følge noen regler for å velge en standard.
Merk til slutt i neste enhet at vi ikke vil bruke @JoinColumn kommentar der. Dette er fordi vi bare trenger det på eie side av det utenlandske nøkkelforholdet. Enkelt sagt, hvem som helst eier den utenlandske nøkkelkolonnen får @JoinColumn kommentar.
De Adresse enhet viser seg å være litt enklere:
@Entity @Table (name = "address") public class Address {@Id @GeneratedValue (strategy = GenerationType.AUTO) @Column (name = "id") private Lang id; // ... @OneToOne (mappedBy = "adresse") privat brukerbruker; // ... getters og setters}
Vi må også plassere @OneToOne kommentar her også. Det er fordi dette er et toveis forhold. Adressesiden av forholdet kalles ikke-eier side.
4. Bruke en delt primærnøkkel
4.1. Modellering med en delt primærnøkkel
I denne strategien, i stedet for å opprette en ny kolonne adresse_id, Vi markerer hovednøkkelenkolonne (bruker-ID) av adressetabell som den utenlandske nøkkelen til brukere bord:
Vi har optimalisert lagringsplassen ved å benytte det faktum at disse enhetene har et en-til-en forhold mellom seg.
4.2. Implementering med en delt primærnøkkel i JPA
Legg merke til at definisjonene våre endres bare litt:
@Entity @Table (name = "brukere") offentlig klasse bruker {@Id @GeneratedValue (strategi = GenerationType.AUTO) @Column (name = "id") privat Lang id; // ... @OneToOne (mappedBy = "bruker", cascade = CascadeType.ALL) @PrimaryKeyJoinColumn privat adresse adresse; // ... getters og setters}
@Entity @Table (name = "address") public class Address {@Id @Column (name = "user_id") private Lang id; // ... @OneToOne @MapsId @JoinColumn (name = "user_id") privat brukerbruker; // ... getters og setters}
De kartlagt av attributt flyttes nå til Bruker klasse siden den utenlandske nøkkelen nå er til stede i adresse bord. Vi har også lagt til de @PrimaryKeyJoinColumn merknad, som indikerer at hovednøkkelen til Bruker enhet brukes som den utenlandske nøkkelverdien for den tilknyttede Adresse enhet.
Vi må fremdeles definere en @Id felt i Adresse klasse, men merk deg at dette refererer til bruker-ID kolonnen, og den bruker ikke lenger @GeneratedValue kommentar. Også på feltet som refererer til Bruker, har vi lagt til de @MapsId kommentar, som indikerer at de primære nøkkelverdiene blir kopiert fra Bruker enhet.
5. Bruke et sammenføyningstabell
En-til-en-tilordninger kan være av to typer - Valgfri og Påbudt, bindende. Så langt har vi bare sett obligatoriske forhold.
La oss nå se for oss at våre ansatte blir tilknyttet en arbeidsstasjon. Det er en-til-en, men noen ganger har en ansatt kanskje ikke en arbeidsstasjon og omvendt.
5.1. Modellering med et sammenføyningsbord
Strategiene vi har diskutert til nå tvinge oss til å sette nullverdier i kolonnen for å håndtere valgfrie forhold.
Vanligvis tenker vi på mange-til-mange-forhold når vi vurderer et sammenføyningstabell, men ved å bruke en sammenføyningstabell, i dette tilfellet, kan det hjelpe oss å eliminere disse nullverdiene:
Nå, når vi har et forhold, vil vi gjøre en oppføring i emp_workstation bord og unngå nullhelt.
5.2. Implementering med et Join Table i JPA
Vårt første eksempel brukt @JoinColumn. Denne gangen bruker vi @JoinTable:
@Entity @Table (name = "ansatte") offentlig klasse Ansatt {@Id @GeneratedValue (strategi = GenerationType.AUTO) @Column (name = "id") privat Lang id; // ... @OneToOne (cascade = CascadeType.ALL) @JoinTable (name = "emp_workstation", joinColumn = {@JoinColumn (name = "ansatte_id", referertColumnName = "id")}, inverseJoinColumn = {@JoinColumn (navn = "workstation_id", referertColumnName = "id")}) privat WorkStation workStation; // ... getters og setters}
@Entity @Table (name = "workstation") offentlig klasse WorkStation {@Id @GeneratedValue (strategi = GenerationType.AUTO) @Column (name = "id") privat Lang id; // ... @OneToOne (mappedBy = "workStation") privat ansatt ansatt; // ... getters og setters}
@Bli med på bordet instruerer dvalemodus om å benytte strategien for å delta i bordet mens du opprettholder forholdet.
Også, Ansatt er eieren av dette forholdet da vi valgte å bruke merket om å bli med på tabellen.
6. Konklusjon
I denne opplæringen lærte vi forskjellige måter å opprettholde en en-til-en-forening i JPA og Hibernate, og når vi skulle bruke hver.
Kildekoden til denne veiledningen finner du på GitHub.