Hibernált öröklési térképezés

1. Áttekintés

A relációs adatbázisoknak nincs egyszerű módja az osztályhierarchiák leképezésére az adatbázis-táblákra.

Ennek megoldására a JPA specifikációja számos stratégiát tartalmaz:

  • MappedSuperclass - a szülőosztályok nem lehetnek entitások
  • Single Table - a különböző osztályokból származó, közös ősökkel rendelkező entitások egyetlen táblázatba kerülnek
  • Csatlakozott tábla - minden osztálynak megvan a maga táblája, és egy alosztály entitás lekérdezéséhez csatlakozni kell a táblákhoz
  • Osztályonkénti tábla - az osztály összes tulajdonsága benne van a táblázatban, ezért nincs szükség csatlakozásra

Minden stratégia más és más adatbázis-struktúrát eredményez.

Az entitás-öröklés azt jelenti, hogy polimorf lekérdezéseket használhatunk az összes alosztály-entitás lekérdezéséhez, amikor lekérdezünk egy szuperosztályt.

Mivel a Hibernate egy JPA megvalósítás, az összes fentieket, valamint néhány, az örökléssel kapcsolatos Hibernate-specifikus funkciót tartalmaz.

A következő szakaszokban részletesebben áttekintjük az elérhető stratégiákat.

2. MappedSuperclass

Használni a MappedSuperclass stratégia, az öröklődés csak az osztályban nyilvánvaló, az entitásmodell nem.

Kezdjük azzal, hogy létrehozunk egy Személy osztály, amely egy szülő osztályt képvisel:

@MappedSuperclass public class Person {@Id private long personId; privát karakterlánc neve; // kivitelező, getters, setters}

Figyelje meg, hogy ennek az osztálynak már nincs @Entity annotáció, mivel önmagában nem fog fennmaradni az adatbázisban.

Ezután adjunk hozzá egy Munkavállaló alosztály:

@Entity nyilvános osztály A MyEmployee kiterjeszti a Person {private String vállalatot; // kivitelező, getters, setters}

Az adatbázisban ez megfelel egynek „MyEmployee” három oszlopos táblázat az alosztály deklarált és örökölt mezőihez.

Ha ezt a stratégiát használjuk, az ősök nem tartalmazhatnak társításokat más entitásokkal.

3. Egy asztal

Az Egységes tábla stratégia egy táblázatot hoz létre minden osztályhierarchiához. Ez a JPA által választott alapértelmezett stratégia is, ha nem határozunk meg kifejezetten ilyet.

A hozzáadásával meghatározhatjuk a használni kívánt stratégiát @Öröklés kommentár a szuperosztályhoz:

@Entity @Inheritance (strategy = InheritanceType.SINGLE_TABLE) public class MyProduct {@Id private long productId; privát karakterlánc neve; // kivitelező, getters, setters}

Az entitások azonosítóját a szuperosztály is meghatározza.

Ezután felvehetjük az alosztály entitásokat:

A @Entity public class Book kiterjeszti a MyProduct {private String szerzőjét; }
A @Entity public class Pen kiterjeszti a MyProduct {private String színt; }

3.1. Diszkriminátor értékek

Mivel az összes entitás rekordjai ugyanabban a táblázatban lesznek, A hibernált módnak meg kell különböztetni őket.

Alapértelmezésben ez egy úgynevezett diszkriminátor oszlopon keresztül történik DTYPE amelynek értéke az entitás neve.

A diszkriminátor oszlop testreszabásához használhatjuk a @DiscriminatorColumn kommentár:

@Entity (név = "termékek") @ Öröklés (stratégia = ÖrökségTípus.SINGLE_TABLE) @DiscriminatorColumn (név = "termék_típus", discriminatorType = DiszkriminátorTípus.INTEGER) nyilvános osztály MyProduct {// ...}

Itt választottunk különbséget MyProduct alosztályú entitásokat egy egész szám oszlop nevű Terméktípus.

Ezután meg kell mondanunk a Hibernate számára, hogy az egyes alosztályok rekordjai milyen értékkel bírnak a Terméktípus oszlop:

A @Entity @DiscriminatorValue ("1") nyilvános osztályú könyv kiterjeszti a MyProductot {// ...}
@Entity @DiscriminatorValue ("2") public class Pen kiterjeszti a MyProduct-ot {// ...}

A hibernálás két további előre definiált értéket ad hozzá, amelyeket a megjegyzés igénybe vehet:nulla”És„nem nulla“:

  • @DiscriminatorValue („null”) - azt jelenti, hogy minden megkülönböztető érték nélküli sor hozzá lesz rendelve az entitásosztályhoz ezzel a feljegyzéssel; ez alkalmazható a hierarchia gyökérosztályára
  • @DiscriminatorValue („nem null”) - minden olyan megkülönböztető értékű sor, amely nem felel meg az entitásmeghatározásokhoz társítottak egyikének sem, az osztályhoz lesz hozzárendelve ezzel a kommentárral

Oszlop helyett használhatjuk a Hibernate-specifikusat is @DiscriminatorFormula kommentár a differenciáló értékek meghatározásához:

@Entity @Inheritance (strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorFormula ("eset, amikor a szerző nem null, akkor 1 másik 2 vége") nyilvános osztály MyProduct {...}

Ennek a stratégiának az az előnye, hogy a polimorf lekérdezés teljesít, mivel a szülő entitások lekérdezéséhez csak egy táblához kell hozzáférni. Másrészt ez azt is jelenti már nem használhatjuk NEM NULLA alosztályra vonatkozó korlátozások entitás tulajdonságai.

4. Csatlakozott táblázat

Ezt a stratégiát használva a hierarchia minden osztálya hozzárendelésre kerül a táblájához. Az egyetlen oszlop, amely többször is megjelenik az összes táblázatban, az az azonosító, amelyet szükség esetén a csatlakozáshoz használunk.

Hozzunk létre egy szuper osztályt, amely ezt a stratégiát használja:

@Entity @Inheritance (strategy = InheritanceType.JOINED) public class Animal {@Id private long animalId; magán húrfajok; // kivitelező, getters, setters}

Ezután egyszerűen meghatározhatunk egy alosztályt:

@Entity public class Kisállat kiterjeszti Animal {private String name; // kivitelező, getters, setters}

Mindkét asztalhoz tartozik egy animalId azonosító oszlop. A. Elsődleges kulcsa Házi kedvenc az entitásnak idegen kulcsra vonatkozó kényszere van az anyavállalat elsődleges kulcsával szemben is. Az oszlop testreszabásához hozzáadhatjuk a @PrimaryKeyJoinColumn kommentár:

@Entity @PrimaryKeyJoinColumn (name = "petId") nyilvános osztály Kisállat kiterjeszti az állatot {// ...}

Ennek az öröklési leképezési módszernek az a hátránya, hogy az entitások beolvasásához táblák közötti összekapcsolásra van szükség, ami nagyszámú rekord esetén alacsonyabb teljesítményt eredményezhet.

A csatlakozások száma magasabb, ha lekérdezzük a szülő osztályt, mivel minden egyes kapcsolódó gyermekhez csatlakozni fog - tehát a teljesítményt nagyobb valószínűséggel befolyásolja, annál magasabb hierarchiában, amelyen rekordokat szeretnénk letölteni.

5. Táblázat osztályonként

A Táblázat osztályonként stratégia minden entitást a táblájához térképez, amely tartalmazza az entitás összes tulajdonságát, beleértve az örökölt tulajdonságokat is.

Az így kapott séma hasonló az alkalmazott sémához @MappedSuperclass, de ettől eltérően az osztályonkénti táblázat valóban meghatározza az entitásokat a szülőosztályok számára, lehetővé téve ezzel az asszociációkat és a polimorf lekérdezéseket.

A stratégia használatához csak hozzá kell adnunk a @Öröklés kommentár az alaposztályhoz:

@Entity @Inheritance (strategy = InheritanceType.TABLE_PER_CLASS) public class Jármű {@Id private long vehicleId; saját húr gyártója; // szabványos kivitelező, mérőeszközök, beállítók}

Ezután létrehozhatjuk az alosztályokat a szokásos módon.

Ez nem nagyon különbözik az egyes entitások puszta feltérképezésétől öröklés nélkül. A megkülönböztetés nyilvánvaló az alaposztály lekérdezésénél, amely az összes alosztályrekordot is visszaadja az a használatával UNIÓ nyilatkozat a háttérben.

A ... haszna UNIÓ alacsonyabb teljesítményhez is vezethet e stratégia kiválasztásakor. Más kérdés, hogy már nem tudjuk használni az identitáskulcsok létrehozását.

6. Polimorf lekérdezések

Mint említettük, egy alaposztály lekérdezésével az összes alosztály-entitást is lekérjük.

Lássuk ezt a viselkedést egy JUnit-teszt során:

@Test public void givenSubclasses_whenQuerySuperclass_thenOk () {Book book = new Book (1, "1984", "George Orwell"); session.save (könyv); Toll toll = új Toll (2, "tollam", "kék"); munkamenet.mentés (toll); assertThat (session.createQuery ("a MyProduct-tól") .getResultList ()). hasSize (2); }

Ebben a példában kettőt hoztunk létre Könyv és Toll tárgyakat, majd megkérdezték szuperosztályukat MyProduct hogy ellenőrizzük, hogy két objektumot kapunk-e.

A hibernált állapot olyan interfészeket vagy alaposztályokat is lekérdezhet, amelyek nem entitások, de az entitásosztályok kiterjesztik vagy megvalósítják őket. Lássunk egy JUnit tesztet a mi segítségével @MappedSuperclass példa:

@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); }

Ne feledje, hogy ez minden szuperosztály vagy interfész esetében is működik, függetlenül attól, hogy a @MappedSuperclass vagy nem. A különbség a szokásos HQL lekérdezéssel szemben az, hogy a teljesen minősített nevet kell használnunk, mivel nem Hibernate által kezelt entitások.

Ha nem akarjuk, hogy egy alosztályt ilyen típusú lekérdezés adja vissza, akkor csak a hibernált állapotot kell hozzáadnunk @Polimorfizmus annotáció a definíciójához, típusával KIFEJEZETT:

@Entity @Polymorphism (type = PolymorphismType.EXPLICIT) public class Bag végrehajtja a (z) {...} elemet

Ebben az esetben, amikor lekérdezi Tételek, a Táska a rekordokat nem küldjük vissza.

7. Következtetés

Ebben a cikkben bemutattuk az öröklés feltérképezésének különböző stratégiáit a hibernált állapotban.

A példák teljes forráskódja megtalálható a GitHub oldalon.