JDO – vztahy mezi objekty
Podkladem pro návrh struktury objektové databáze bývá obvykle diagram tříd, který popisuje jednotlivé třídy v aplikační doméně, jejich vlastnosti a vzájemné vztahy. Dosud jsme se při práci s JDO zaměřovali na jednotlivé třídy, v tomto článku se podíváme blíže na implementaci vztahů mezi třídami.
Objektový návrh aplikací dnes probíhá převážně s využitím jazyka UML (Unified Modelling Language). Pro návrh databáze je podstatný zejména diagram tříd, který v grafické podobě reprezentuje jednotlivé třídy a jejich vztahy. Vztahy mezi objekty dvou různých tříd A
a B
lze z pohledu objektové databáze rozdělit do následujících skupin:
- Vztahy 1:1 – ke každému objektu třídy
A
přísluší právě jeden objekt třídyB
. - Vztahy 1:N – ke každému objektu třídy
A
může příslušet více objektů třídyB
. V diagramu tříd lze tento vztah dále konkretizovat, například zda je příslušných objektů třídyB
jeden a více, či zda nemusí být ani jeden. - Vztahy M:N – ke každému objektu třídy
A
může příslušet více objektů třídyB
a zároveň ke každému objektu třídyB
může příslušet více různých objektů třídyA
.
Jednotlivé typy vztahů se liší zejména způsobem jejich implementace v Javě a JDO a z pohledu úložiště objektů i způsobem vnitřní reprezentace, o které je v případě JDO nutné mít alespoň obecnou představu.
Vztahy 1:1
Vztahy 1:1 mohou být v zásadě dvojího druhu. První a běžnější variantou je takzvaný jednostranný (single-ended) vztah, kdy objekt třídy A
obsahuje informaci o příslušném objektu třídy B
. Druhou variantu představuje takzvaný oboustranný vztah, kdy navíc i objekt B
obsahuje informaci o objektu třídy A
, ke kterému přísluší. Uvažujme jednoduchý případ, kdy evidujeme pojistky povinného ručení motorových vozidel. U vztahu vozidlo – pojistka se zjevně jedná o vztah 1:1. Podívejme se na to, jak v praxi realizujeme jednostrannou i oboustrannou variantu tohoto vztahu.
Jednostranný vztah
Jako příklad si uveďme následující vztah tříd Vozidlo
a Pojistka
:
V tomto příkladě obsahuje třída Vozidlo
položku pojistka
, která obsahuje odpovídající objekt třídy Pojistka
. Metadata pro obě třídy mohou vypadat například takto:
<package name=“ruceni“>
<class name=“Vozidlo“ identity-type=“datastore“>
<field name=“SPZ“ persistence-modifier=“persistent“>
<extension vendor-name=“jpox“ key=“length“ value=“max 10″/>
</field>
<field name=“pojistka“ persistence-modifier=“persistent“>
</field>
</class>
<class name=“Pojistka“ identity-type=“datastore“>
<field name=“cislo“ persistence-modifier=“persistent“>
<extension vendor-name=“jpox“ key=“length“ value=“max 50″/>
</field>
<field name=“castka“ persistence-modifier=“persistent“>
</field>
…
</class>
</package>
Oboustranný vztah
V případě oboustranného vztahu přibude ve třídě Pojistka
položka vozidlo
, která bude obsahovat objekt reprezentující příslušné vozidlo:
Obdobně se nová položka vozidlo
objeví i v metadatech. Oboustranné vztahy se doporučuje používat pouze v nezbytných případech a se značnou dávkou opatrnosti. Při vkládání takových objektů do databáze totiž nastává situace, kdy jeden z objektů je již v databázi a druhý dosud nebyl vložen, takže první objekt se odkazuje na neplatný objekt. Proto je vhodné nejprve vložit oba objekty do databáze s prázdnými referencemi na ostatní objekty a teprve následně nastavit hodnoty příslušných vlastností.
Vztahy 1:N
U vztahů 1:N je jednomu objektu třídy A
přiřazeno více objektů třídy B
, případně můžeme připustit i prázdnou množinu objektů třídy B
(kardinalita vztahu je 0..N
). Existují tři možnosti jak vyjádřit tento vztah v JDO:
- Normální mapování – třída
A
obsahuje jako atribut kolekci objektů třídyB
. - Jednostranné inverzní mapování – každý z objektů třídy
B
obsahuje jako atribut objekt třídyA
, se kterým je v relaci. - Oboustranné inverzní mapování – kombinace předchozích dvou možností.
Podle konkrétních požadavků lze použít libovolnou kolekci podporovanou JDO, tedy množinu, seznam nebo mapu, či některou z jejich podtříd.
Normální mapování
Jedná se o nejběžnější druh mapování. Jeho hlavní výhodou je, že není třeba žádných zvláštních rozšíření JDO, zcela vystačíme s použitím kolekcí v té formě, jak byly popsány v předchozím článku. Ukažme si jednoduchý příklad. Mějme vztah majitel – vozidlo, kde jedno vozidlo má vždy jednoho majitele, ale jeden majitel může vlastnit více vozidel:
Metadata pro tyto třídy budou v tomto případě vypadat následovně:
<package name=“demo“>
<class name=“Osoba“ identity-type=“datastore“>
<field name=“jmeno“ persistence-modifier=“persistent“>
<extension vendor-name=“jpox“ key=“length“ value=“max 50″/>
</field>
<field name=“prijmeni“ persistence-modifier=“persistent“>
<extension vendor-name=“jpox“ key=“length“ value=“max 50″/>
</field>
<field name=“vozidla“ persistence-modifier=“persistent“>
<collection element-type=“Vozidlo“/>
</field>
</class>
<class name=“Vozidlo“ identity-type=“datastore“>
<field name=“SPZ“ persistence-modifier=“persistent“>
<extension vendor-name=“jpox“ key=“length“ value=“max 10″/>
</field>
</class>
</package>
Drobným nedostatkem normálního mapování je, že v případě jeho projekce do relační databáze vznikají tři tabulky – první tabulka pro třídu vlastníka, druhá tabulka pro třídu prvků kolekce a třetí tabulka spojovací (join table), která vzájemně přiřazuje objekty těchto dvou tříd. Pokud z nějakého důvodu chceme vystačit se dvěma tabulkami, je třeba použít inverzní mapování.
Jednostranné inverzní mapování
U jednostranného inverzního mapování třída A
(v předchozím příkladě třída Osoba
) neuchovává žádné informace o přiřazených objektech třídy B
. Naopak každý objekt třídy B
obsahuje informaci o tom, ke kterému objektu třídy A
přísluší. Tento typ relace není většinou implementací podporován, obvykle se upřednostňuje podpora oboustranného inverzního mapování, vůči kterému nepřináší jednostranné mapování žádné podstatné výhody.
Oboustranné inverzní mapování
Oboustranné mapování představuje kombinaci obou předchozích. Třída A
obsahuje kolekci příslušejících objektů třídy B
a zároveň každý prvek třídy B
obsahuje jako atribut objekt třídy A
, ke kterému přísluší. Předchozí příklad pro tuto variantu upravíme tak, že třídě Vozidlo
přidáme atribut vlastnik
. Dostaneme následující diagram:
V metadatech bude úprava poněkud složitější, protože musíme specifikovat, které z atributů jsou použity pro mapování. V našem případě jde o kolekci vozidla
ve třídě Osoba
a atribut vlastnik
ve třídě Vozidlo
. Metadata potom budou vypadat následovně:
<package name=“demo“>
<class name=“Osoba“ identity-type=“datastore“>
<field name=“jmeno“ persistence-modifier=“persistent“>
<extension vendor-name=“jpox“ key=“length“ value=“max 50″/>
</field>
<field name=“prijmeni“ persistence-modifier=“persistent“>
<extension vendor-name=“jpox“ key=“length“ value=“max 50″/>
</field>
<field name=“vozidla“ persistence-modifier=“persistent“>
<collection element-type=“Vozidlo“>
<extension vendor-name=“jpox“
key=“owner-field“
value=“vlastnik“/>
</collection>
</field>
</class>
<class name=“Vozidlo“ identity-type=“datastore“>
<field name=“SPZ“ persistence-modifier=“persistent“>
<extension vendor-name=“jpox“ key=“length“ value=“max 10″/>
</field>
<field name=“vlastnik“ persistence-modifier=“persistent“>
<extension vendor-name=“jpox“
key=“collection-field“
value=“vozidla“/>
</field>
</class>
</package>
Jak je patrné z příkladu, tvar specifikace opět není standardizován v JDO 1.0.1 a využívá se proto proprietárních rozšíření. Příklad ukazuje tvar specifikace pro JPOX. Na jedné straně u kolekce zadáme jmeno „protějšího“ atributu pomocí rozšíření owner-field
, na druhé straně pak naopak zadáme název kolekce pomocí rozšíření collection-field
. V jiných implementacích JDO se tato rozšíření jmenují různě a je třeba je nalézt v dokumentaci. Například u komerční implementace Kodo (vendor-name="kodo"
) se používá inverse-owner
místo owner-field
a Speedo používá název reverse-field
.
U oboustranného mapování není zapotřebí vytvářet v relační databázi spojovací tabulku, neboť vztahy objektů jsou uloženy přímo v atributech třídy B
.
Relace M:N
Vztah M:N přiřazuje každému objektu třídy A
více objektů třídy B
a zároveň každému objektu třídy B
více objektů třídy A
. V tomto případě se obvykle používá mapování, které jsme v předchozích případech označovali jako normální, tedy každý z objektů obsahuje kolekci příslušejících objektů:
V metadatech se kolekce projeví stejným způsobem jako u normálního mapování 1:N, tedy pro každou kolekci je nutno pouze specifikovat třídu objektů v ní obsažených.
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Mohlo by vás také zajímat
-
Jak si vyzkoušet Apple Intelligence v EU
2. srpna 2024 -
OpenAI představilo novou funkci ChatGPT Search
6. listopadu 2024 -
Optimalizace a zlepšení výkonu kódu: tipy a triky
14. srpna 2023 -
Nejlevnější VPS: To je nový Cloud Server Mini od ZonerCloud
4. června 2024
Nejnovější
-
Výkonný a kompaktní: ASOME Max Studio s výjimečným poměrem cena/výkon
11. listopadu 2024 -
Šokující data od Microsoftu: Kyberútoky rostou o stovky procent!
8. listopadu 2024 -
Chcete jedinečnou doménu? Objevte koncovky FOOD, MEME a MUSIC!
7. listopadu 2024 -
OpenAI představilo novou funkci ChatGPT Search
6. listopadu 2024