Dvalemodus i arvemodus

1. Oversikt

Relasjonsdatabaser har ikke en enkel måte å kartlegge klassehierarkier på databasetabeller.

For å løse dette gir JPA-spesifikasjonen flere strategier:

  • Kartlagt Superklasse - foreldreklassene, kan ikke være enheter
  • Enkeltbord - enhetene fra forskjellige klasser med felles forfedre plasseres i et enkelt bord
  • Sammenføyet tabell - hver klasse har sin tabell og spørring etter en underklasseenhet krever at du blir med i tabellene
  • Tabell per klasse - alle egenskapene til en klasse ligger i tabellen, så det er ikke nødvendig å delta

Hver strategi resulterer i en annen databasestruktur.

Enhetsarv betyr at vi kan bruke polymorfe spørsmål for å hente alle underklassenheter når vi spør etter en superklasse.

Siden Hibernate er en JPA-implementering, inneholder den alle de ovennevnte i tillegg til noen få Hibernate-spesifikke funksjoner knyttet til arv.

I de neste avsnittene vil vi gå nærmere over tilgjengelige strategier.

2. Kartlagt Superklasse

Bruker Kartlagt Superklasse strategi, arv er bare tydelig i klassen, men ikke enhetsmodellen.

La oss starte med å lage en Person klasse som vil representere en overordnet klasse:

@MappedSuperclass offentlig klasse person {@Id privat lang personId; privat strengnavn; // constructor, getters, setters}

Legg merke til at denne klassen ikke lenger har en @Enhet kommentar, da det ikke vil være vedvarende i databasen av seg selv.

La oss deretter legge til en Ansatt underklasse:

@Entity offentlig klasse MyEmployee utvider Person {private String company; // constructor, getters, setters}

I databasen vil dette tilsvare en “Min medarbeider” tabell med tre kolonner for deklarerte og nedarvede felt i underklassen.

Hvis vi bruker denne strategien, kan ikke forfedre inneholde tilknytning til andre enheter.

3. Enkeltbord

Single Table-strategien oppretter en tabell for hvert klassehierarki. Dette er også standardstrategien valgt av JPA hvis vi ikke spesifiserer en eksplisitt.

Vi kan definere strategien vi ønsker å bruke ved å legge til @Arv kommentar til superklassen:

@Entity @Inheritance (strategi = InheritanceType.SINGLE_TABLE) offentlig klasse MyProduct {@Id private long productId; privat strengnavn; // constructor, getters, setters}

Enhetens identifikator er også definert i superklassen.

Deretter kan vi legge til underklassenheter:

@Entity public class Book utvider MyProduct {private strengforfatter; }
@Entity offentlig klasse Penn utvider MyProduct {private String farge; }

3.1. Diskriminatorverdier

Siden postene for alle enheter vil være i samme tabell, Dvalemodus trenger en måte å skille mellom dem.

Som standard gjøres dette gjennom en diskriminatorkolonne kalt DTYPE som har navnet på enheten som en verdi.

For å tilpasse diskriminatorkolonnen, kan vi bruke @DiscriminatorColumn kommentar:

@Entity (name = "products") @ Arv (strategi = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn (name = "product_type", discriminatorType = DiscriminatorType.INTEGER) offentlig klasse MyProduct {// ...}

Her har vi valgt å skille MyProduct underklassenheter av en heltall kolonne kalt Produkttype.

Deretter må vi fortelle dvalemodus hvilken verdi hver underklassepost vil ha for Produkttype kolonne:

@Entity @DiscriminatorValue ("1") public class Book utvider MyProduct {// ...}
@Entity @DiscriminatorValue ("2") offentlig klasse Pen utvider MyProduct {// ...}

Dvalemodus legger til to andre forhåndsdefinerte verdier som kommentaren kan ta: “null”Og”ikke null“:

  • @DiscriminatorValue (“null”) - betyr at enhver rad uten en diskriminerende verdi vil bli kartlagt til enhetsklassen med denne kommentaren; dette kan brukes på rotklassen i hierarkiet
  • @DiscriminatorValue (“ikke null”) - Enhver rad med en diskriminerende verdi som ikke samsvarer med noen av de som er knyttet til enhetsdefinisjoner, blir kartlagt til klassen med denne kommentaren

I stedet for en kolonne kan vi også bruke den spesifikke dvalemodus @DiscriminatorFormula kommentar for å bestemme de differensierende verdiene:

@Entity @Inheritance (strategi = InheritanceType.SINGLE_TABLE) @DiscriminatorFormula ("tilfelle når forfatteren ikke er null da en annen 2 slutt") offentlig klasse MyProduct {...}

Denne strategien har fordelen av ytelse med polymorfe søk siden det kun er tilgang til én tabell når du spør om foreldreenheter. På den annen side betyr dette også det vi kan ikke lenger bruke IKKE NULL begrensninger på underklasse enhetsegenskaper.

4. Sammenføyde bord

Ved hjelp av denne strategien blir hver klasse i hierarkiet kartlagt til bordet. Den eneste kolonnen som gjentatte ganger vises i alle tabellene er identifikatoren, som vil bli brukt til å bli med dem når det er nødvendig.

La oss lage en superklasse som bruker denne strategien:

@Entity @Inheritance (strategi = InheritanceType.JOINED) offentlig klasse Animal {@Id private long animalId; private String arter; // constructor, getters, setters}

Deretter kan vi ganske enkelt definere en underklasse:

@Entity offentlig klasse Pet extends Animal {private String name; // constructor, getters, setters}

Begge bordene vil ha en animalId identifikasjonskolonne. Den primære nøkkelen til Kjæledyr enhet har også en utenlandsk nøkkelbegrensning til hovednøkkelen til morselskapet. For å tilpasse denne kolonnen kan vi legge til @PrimaryKeyJoinColumn kommentar:

@Entity @PrimaryKeyJoinColumn (name = "petId") offentlig klasse Pet extends Animal {// ...}

Ulempen med denne arvkartleggingsmetoden er at det å hente enheter krever sammenkoblinger mellom tabellene, som kan resultere i lavere ytelse for et stort antall poster.

Antall sammenkoblinger er høyere når du spør etter foreldreklassen, ettersom det vil bli med hvert enkelt relatert barn - slik at ytelsen er mer sannsynlig å bli påvirket jo høyere opp i hierarkiet vi vil hente poster.

5. Tabell per klasse

Tabellen per klasse-strategi kartlegger hver enhet til sin tabell som inneholder alle egenskapene til enheten, inkludert de arvede.

Det resulterende skjemaet ligner på det som brukes @MappedSuperclass, men i motsetning til det, vil tabell per klasse faktisk definere enheter for overordnede klasser, slik at assosiasjoner og polymorfe spørsmål som et resultat.

For å bruke denne strategien trenger vi bare å legge til @Arv kommentar til basisklassen:

@Entity @Inheritance (strategi = InheritanceType.TABLE_PER_CLASS) offentlig klasse kjøretøy {@Id privat lang kjøretøyId; privat streng produsent; // standard konstruktør, getters, setters}

Deretter kan vi lage underklassene på standard måte.

Dette er ikke veldig forskjellig fra å bare kartlegge hver enhet uten arv. Skillet er tydelig når du spør etter basisklassen, som også returnerer alle underklassepostene ved å bruke a UNION uttalelse i bakgrunnen.

Bruken av UNION kan også føre til dårligere ytelse når du velger denne strategien. En annen sak er at vi ikke lenger kan bruke identitetsnøkkelgenerering.

6. Polymorfe spørsmål

Som nevnt vil spørring etter en basisklasse også hente alle underklassenheter.

La oss se denne oppførselen i aksjon med en JUnit-test:

@Test public void givenSubclasses_whenQuerySuperclass_thenOk () {Book book = new Book (1, "1984", "George Orwell"); session.save (bok); Pennepenn = ny penn (2, "pennen min", "blå"); session.save (penn); assertThat (session.createQuery ("fra MyProduct") .getResultList ()). hasSize (2); }

I dette eksemplet har vi opprettet to Bok og Penn gjenstander, og deretter spurte superklassen sin MyProduct for å bekrefte at vi henter to objekter.

Dvalemodus kan også spørre grensesnitt eller baseklasser som ikke er enheter, men utvides eller implementeres av enhetsklasser. La oss se en JUnit-test ved hjelp av vår @MappedSuperclass eksempel:

@Test offentlig ugyldighet givenSubclasses_whenQueryMappedSuperclass_thenOk () {MyEmployee emp = new MyEmployee (1, "john", "baeldung"); session.save (emp); assertThat (session.createQuery ("fra com.baeldung.hibernate.pojo.inheritance.Person") .getResultList ()) .hasSize (1); }

Merk at dette også fungerer for alle superklasser eller grensesnitt, enten det er en @MappedSuperclass eller ikke. Forskjellen fra et vanlig HQL-spørsmål er at vi må bruke det fullstendige navnet, siden de ikke er dvalestyrte enheter.

Hvis vi ikke vil at en underklasse skal returneres av denne typen spørsmål, trenger vi bare å legge til dvalemodus @Polymorfisme kommentar til definisjonen, med type FORKLARING:

@Entity @Polymorphism (type = PolymorphismType.EXPLICIT) offentlig klasse Bag implementerer Element {...}

I dette tilfellet når du spør etter Varer, de Bag postene blir ikke returnert.

7. Konklusjon

I denne artikkelen har vi vist de forskjellige strategiene for å kartlegge arv i dvalemodus.

Den fulle kildekoden til eksemplene finner du på GitHub.


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