Mapovanie dedičstva dlhodobého spánku

1. Prehľad

Relačné databázy nemajú priamy spôsob mapovania hierarchií tried na databázové tabuľky.

Za týmto účelom poskytuje špecifikácia JPA niekoľko stratégií:

  • MappedSuperclass - nadradené triedy, nemôžu to byť entity
  • Jedna tabuľka - entity z rôznych tried so spoločným predkom sú umiestnené v jednej tabuľke
  • Pripojená tabuľka - každá trieda má svoju tabuľku a dopytovanie entity podtriedy si vyžaduje pripojenie k tabuľkám
  • Table-Per-Class - všetky vlastnosti triedy sú v jej tabuľke, takže nie je potrebné žiadne spojenie

Výsledkom každej stratégie je iná štruktúra databázy.

Dedičnosť entít znamená, že pri vyhľadávaní nadtriedy môžeme na získanie všetkých entít podtriedy použiť polymorfné dotazy.

Pretože Hibernate je implementácia JPA, obsahuje všetky vyššie uvedené a tiež niekoľko funkcií špecifických pre Hibernate týkajúcich sa dedenia.

V ďalších častiach si podrobnejšie prejdeme dostupné stratégie.

2. MappedSuperclass

Pomocou MappedSuperclass Stratégia je dedičnosť zrejmá iba v triede, ale nie v modeli entity.

Začnime vytvorením a Osoba trieda, ktorá bude predstavovať nadradenú triedu:

@MappedSuperclass verejná trieda Osoba {@Id súkromná dlhá osobaId; súkromné ​​meno reťazca; // konštruktor, getri, nastavovatelia}

Všimnite si, že táto trieda už nemá @Entity anotácia, pretože sám o sebe nebude v databáze pretrvávať.

Ďalej pridajme Zamestnanec podtrieda:

@Entity public class MyEmployee rozširuje Person {private String company; // konštruktor, getri, nastavovatelia}

V databáze to bude zodpovedať jednému „Zamestnanec“ tabuľka s tromi stĺpcami pre deklarované a zdedené polia podtriedy.

Ak používame túto stratégiu, predkovia nemôžu obsahovať asociácie s inými entitami.

3. Jeden stôl

Stratégia Single Table vytvára jednu tabuľku pre každú hierarchiu tried. Toto je tiež predvolená stratégia zvolená Spoločným parlamentným zhromaždením, ak ju neurčíme výslovne.

Stratégiu, ktorú chceme použiť, môžeme definovať pridaním znaku @ Dedenie anotácia k supertriede:

@Entity @Inheritance (strategy = InheritanceType.SINGLE_TABLE) verejná trieda MyProduct {@Id private long productId; súkromné ​​meno reťazca; // konštruktor, getri, nastavovatelia}

V nadtriede je tiež definovaný identifikátor entít.

Potom môžeme pridať entity podtriedy:

@Entity public class Book rozširuje MyProduct {private String author; }
@Entity public class Pen rozširuje MyProduct {private String color; }

3.1. Hodnoty diskriminátora

Pretože záznamy pre všetky subjekty budú v tej istej tabuľke, Hibernate potrebuje spôsob, ako ich rozlíšiť.

Štandardne sa to deje prostredníctvom stĺpca diskriminátora s názvom DTYPE ktorá má názov entity ako hodnotu.

Na prispôsobenie stĺpca diskriminátora môžeme použiť znak @DiscriminatorColumn anotácia:

@Entity (name = "products") @Inheritance (strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn (name = "product_type", discriminatorType = DiscriminatorType.INTEGER) verejná trieda MyProduct {// ...}

Tu sme sa rozhodli rozlišovať MyProduct subjekty podtriedy podľa celé číslo stĺpec s názvom typ produktu.

Ďalej musíme povedať režimu dlhodobého spánku, akú hodnotu bude mať každý záznam podtriedy pre typ produktu stĺpec:

@Entity @DiscriminatorValue ("1") verejná trieda Kniha rozširuje MyProduct {// ...}
@Entity @DiscriminatorValue ("2") verejné triedy Pen rozširuje MyProduct {// ...}

Hibernate pridáva ďalšie dve preddefinované hodnoty, ktoré môže anotácia nadobúdať: „nulový“A„nie null“:

  • @DiscriminatorValue („null“) - znamená, že akýkoľvek riadok bez hodnoty diskriminátora bude s touto anotáciou namapovaný na triedu entít; toto je možné aplikovať na koreňovú triedu hierarchie
  • @DiscriminatorValue („nie null“) - akýkoľvek riadok s hodnotou diskriminátora, ktorý sa nezhoduje so žiadnym z tých, ktoré sú spojené s definíciami entít, bude namapovaný na triedu s touto anotáciou

Namiesto stĺpca môžeme použiť aj špecifický režim dlhodobého spánku @DiscriminatorFormula anotácia na určenie diferenciačných hodnôt:

@Entity @Inheritance (strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorFormula ("prípad, keď autor nemá hodnotu null, potom 1 iný 2 koniec") verejná trieda MyProduct {...}

Táto stratégia má výhodu výkonu polymorfných dotazov, pretože pri dotazovaní na nadradené entity je potrebné pristupovať iba k jednej tabuľke. Na druhej strane to tiež znamená už nemôžeme používať NIE NULL obmedzenia pre podtriedu vlastnosti entity.

4. Pripojená tabuľka

Pomocou tejto stratégie je každá trieda v hierarchii mapovaná do svojej tabuľky. Jediným stĺpcom, ktorý sa opakovane objavuje vo všetkých tabuľkách, je identifikátor, ktorý sa v prípade potreby použije na ich spojenie.

Vytvorme supertriedu, ktorá využíva túto stratégiu:

@Entity @Inheritance (strategy = InheritanceType.JOINED) verejná trieda Zviera {@Id súkromné ​​dlhé zviera ID; súkromné ​​druhy reťazcov; // konštruktor, getri, nastavovatelia}

Potom môžeme jednoducho definovať podtriedu:

@Entity public class Pet rozširuje Animal {private String name; // konštruktor, getri, nastavovatelia}

Oba stoly budú mať animalId stĺpec identifikátora. Primárny kľúč kľúča Domáci miláčik účtovná jednotka tiež má obmedzený cudzí kľúč na primárny kľúč svojej materskej entity. Na prispôsobenie tohto stĺpca môžeme pridať znak @PrimaryKeyJoinColumn anotácia:

@Entity @PrimaryKeyJoinColumn (name = "petId") verejná trieda Pet rozširuje zviera {// ...}

Nevýhodou tejto metódy mapovania dedičstva je, že načítanie entít vyžaduje spojenie medzi tabuľkami, čo môže mať za následok nižší výkon pri veľkom počte záznamov.

Počet pripojení je vyšší pri dotazovaní sa na nadradenú triedu, pretože sa bude spájať s každým príbuzným dieťaťom - takže výkon bude s väčšou pravdepodobnosťou ovplyvnený, čím vyššie v hierarchii chceme načítať záznamy.

5. Stôl na triedu

Stratégia Tabuľka na triedu mapuje každú entitu na jej tabuľku, ktorá obsahuje všetky vlastnosti entity, vrátane zdedených.

Výsledná schéma je podobná schéme, ktorá používa @MappedSuperclass, ale na rozdiel od toho bude tabuľka na triedu skutočne definovať entity pre nadradené triedy, čo vo výsledku umožní asociácie a polymorfné dotazy.

Ak chcete použiť túto stratégiu, stačí pridať @ Dedenie anotácia k základnej triede:

@Entity @Inheritance (strategy = InheritanceType.TABLE_PER_CLASS) verejná trieda Vehicle {@Id private long vehicleId; súkromný výrobca strún; // štandardný konštruktor, getre, setre}

Potom môžeme štandardným spôsobom vytvárať podtriedy.

To sa veľmi nelíši od jednoduchého mapovania každej entity bez dedenia. Rozdiel je zrejmý pri dotazovaní na základnú triedu, ktorá vráti všetky záznamy podtriedy tiež pomocou a ÚNIA vyhlásenie na pozadí.

Použitie ÚNIA môže tiež viesť k horšiemu výkonu pri výbere tejto stratégie. Ďalším problémom je, že už nemôžeme používať generovanie kľúčov identity.

6. Polymorfné dotazy

Ako už bolo spomenuté, pri dotazovaní sa na základnú triedu sa tiež načítajú všetky entity podtriedy.

Pozrime sa na toto správanie v akcii pomocou testu JUnit:

@Test public void givenSubclasses_whenQuerySuperclass_thenOk () {Book book = new Book (1, "1984", "George Orwell"); session.save (kniha); Pero = nové pero (2, „moje pero“, „modré“); session.save (pero); assertThat (session.createQuery ("from MyProduct") .getResultList ()). hasSize (2); }

V tomto príklade sme vytvorili dva Kniha a Pero objekty, potom sa opýtali svojej nadtriedy MyProduct aby sme overili, že získame dva objekty.

Hibernácia môže tiež vyhľadávať rozhrania alebo základné triedy, ktoré nie sú entitami, ale sú rozšírené alebo implementované triedami entít. Pozrime sa na test JUnit pomocou nášho @MappedSuperclass príklad:

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

Všimnite si, že to funguje aj pre akúkoľvek nadtriedu alebo rozhranie, či už je to @MappedSuperclass alebo nie. Rozdiel od bežného dotazu HQL je v tom, že musíme použiť úplný názov, pretože nejde o entity spravované režimom dlhodobého spánku.

Ak nechceme, aby sa podtrieda týmto typom dotazu vrátila, stačí pridať iba režim dlhodobého spánku @ Polymorfizmus anotácia k jeho definícii, s typom VÝSLOVNÁ:

@Entity @Polymorphism (type = PolymorphismType.EXPLICIT) verejná trieda Bag implementuje položku {...}

V takom prípade pri dotazovaní na Položky, the Taška záznamy sa nevrátia.

7. Záver

V tomto článku sme si ukázali rôzne stratégie mapovania dedičstva v režime dlhodobého spánku.

Celý zdrojový kód príkladov nájdete na GitHub.


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