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.