Kartlegge en enkelt enhet til flere tabeller i JPA

Utholdenhetstopp

Jeg kunngjorde nettopp det nye Lær våren kurs, med fokus på det grunnleggende i vår 5 og vårstøvel 2:

>> KONTROLLER KURSET

1. Introduksjon

JPA gjør det mindre smertefullt å håndtere relasjonsdatabasemodeller fra Java-applikasjonene våre. Ting er enkle når vi tilordner hver tabell til en enkelt enhetsklasse. Men noen ganger har vi grunner til å modellere våre enheter og tabeller annerledes:

  • Når vi ønsker å opprette logiske grupper av felt, kan vi kartlegge flere klasser til en enkelt tabell
  • Hvis arv er involvert, kan vi kartlegge et klassehierarki til en tabellstruktur
  • I tilfeller når relaterte felt er spredt mellom flere tabeller, og vi vil modellere disse tabellene med en enkelt klasse

I denne korte opplæringen vil vi se hvordan vi kan takle dette siste scenariet.

2. Datamodell

La oss si at vi driver en restaurant, og vi vil lagre data om hvert måltid vi serverer:

  • Navn
  • beskrivelse
  • pris
  • hva slags allergener den inneholder

Siden det er mange mulige allergener, skal vi gruppere dette datasettet. Videre vil vi også modellere dette ved hjelp av følgende tabelldefinisjoner:

La oss nå se hvordan vi kan tilordne disse tabellene til enheter ved hjelp av standard JPA-merknader.

3. Opprette flere enheter

Den mest åpenbare løsningen er å opprette en enhet for begge klassene.

La oss starte med å definere Måltid enhet:

@Entity @Table (name = "meal") class Meal {@Id @GeneratedValue (strategy = GenerationType.IDENTITY) @Column (name = "id") Lang id; @Column (name = "name") Strengnavn; @Kolonne (navn = "beskrivelse") Beskrivelse av streng; @Column (name = "pris") BigDecimal pris; @OneToOne (mappedBy = "måltid") Allergener allergener; // standard getters og setters}

Deretter legger vi til Allergener enhet:

@Entity @Table (name = "allergens") class Allergens {@Id @GeneratedValue (strategy = GenerationType.IDENTITY) @Column (name = "meal_id") Lang måltidId; @OneToOne @PrimaryKeyJoinColumn (name = "meal_id") Måltidsmåltid; @Column (name = "peanuts") boolske peanøtter; @Column (name = "selleri") boolsk selleri; @Column (name = "sesame_seeds") boolsk sesameSeeds; // standard getters og setters}

I eksemplet ovenfor kan vi se det måltid_id er både hovednøkkelen og også den utenlandske nøkkelen. Det betyr at vi må definere en-til-en-forholdskolonnen ved hjelp av @PrimaryKeyJoinColumn.

Imidlertid har denne løsningen to problemer:

  • Vi vil alltid lagre allergener til et måltid, og denne løsningen håndhever ikke denne regelen
  • Måltids- og allergendataene hører sammen logisk - derfor vil vi kanskje lagre denne informasjonen i samme Java-klasse, selv om vi opprettet flere tabeller for dem

En mulig løsning på det første problemet er å legge til @Ikke null kommentar til allergener felt på vår Måltid enhet. JPA vil ikke la oss vedvare Måltid hvis vi har en nullAllergener.

Dette er imidlertid ikke en ideell løsning; vi ønsker en mer restriktiv, der vi ikke en gang har muligheten til å prøve å vedvare a Måltid uten Allergener.

4. Opprette en enhet med @SecondaryTable

Vi kan opprette en enkelt enhet som angir at vi har kolonner i forskjellige tabeller ved hjelp av @SecondaryTable kommentar:

@Entity @Table (name = "meal") @SecondaryTable (name = "allergens", pkJoinColumns = @PrimaryKeyJoinColumn (name = "meal_id")) klasse Måltid {@Id @GeneratedValue (strategi = GenerationType.IDENTITY) @Column (navn = "id") Lang id; @Column (name = "name") Strengnavn; @Kolonne (navn = "beskrivelse") Beskrivelse av streng; @Column (name = "pris") BigDecimal pris; @Column (name = "peanuts", table = "allergens") boolske peanøtter; @Column (name = "selleri", tabell = "allergener") boolsk selleri; @Column (navn = "sesamfrø", tabell = "allergener") boolsk sesamfrø; // standard getters og setters}

Bak kulissene slutter JPA seg til primærbordet med sekundærtabellen og fyller ut feltene. Denne løsningen ligner på @OneToOne forhold, men på denne måten kan vi ha alle egenskapene i samme klasse.

Det er viktig å merke seg dethvis vi har en kolonne i en sekundær tabell, må vi spesifisere den med bord argument av @Kolonne kommentar. Hvis en kolonne er i primærtabellen, kan vi utelate bord argument som JPA ser som standard etter kolonner i primærtabellen.

Vær også oppmerksom på at vi kan ha flere sekundære tabeller hvis vi legger dem inn @SecondaryTables. Alternativt, fra Java 8, kan vi merke enheten med flere @SecondaryTable kommentarer siden det er en repeterbar kommentar.

5. Kombinere @SecondaryTable Med @En del av

Som vi har sett, @SecondaryTable kartlegger flere tabeller til samme enhet. Det vet vi også @En del av og @Innbyggbar å gjøre det motsatte og kartlegge en enkelt tabell til flere klasser.

La oss se hva vi får når vi kombinerer @SecondaryTable med @En del av og @Embeddable:

@Entity @Table (name = "meal") @SecondaryTable (name = "allergens", pkJoinColumns = @PrimaryKeyJoinColumn (name = "meal_id")) class Meal {@Id @GeneratedValue (strategy = GenerationType.IDENTITY) @Column (name = "id") Lang id; @Column (name = "name") Strengnavn; @Kolonne (navn = "beskrivelse") Beskrivelse av streng; @Column (name = "pris") BigDecimal pris; @Embedded Allergens allergens; // standard getters and setters} @ Embeddable class Allergens {@Column (name = "peanuts", table = "allergens") boolske peanøtter; @Column (name = "selleri", tabell = "allergener") boolsk selleri; @Column (navn = "sesamfrø", tabell = "allergener") boolsk sesamfrø; // standard getters og setters}

Det er en lignende tilnærming til det vi så ved hjelp @OneToOne. Det har imidlertid et par fordeler:

  • JPA administrerer de to bordene sammen for oss, så vi kan være sikre på at det blir en rad for hvert måltid i begge bordene
  • Dessuten er koden litt enklere, siden vi trenger mindre konfigurasjon

Likevel fungerer denne en-til-en-lignende løsningen bare når de to tabellene har samsvarende ID-er.

Det er verdt å nevne at hvis vi ønsker å gjenbruke Allergener klasse, ville det være bedre hvis vi definerte kolonnene i den sekundære tabellen i Måltid klasse med @AttributeOverride.

6. Konklusjon

I denne korte opplæringen har vi sett hvordan vi kan tilordne flere tabeller til samme enhet ved hjelp av @SecondaryTable JPA-kommentar.

Vi så også fordelene med å kombinere @SecondaryTable med @En del av og @Embeddable for å få et forhold som ligner en-til-en.

Som vanlig er eksemplene tilgjengelige på GitHub.

Persistensbunn

Jeg kunngjorde nettopp det nye Lær våren kurs, med fokus på det grunnleggende i vår 5 og vårstøvel 2:

>> KONTROLLER KURSET

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