JDO – dědičnost tříd a pokročilé dotazy
Dědičnost tříd je jednou ze základních vlastností většiny objektově orientovaných jazyků, a proto není důvod ji nevyužít i při návrhu objektové databáze. Podívejme se tedy na to, jak se JDO dokáže vypořádat s dědičností tříd persistentních objektů. Dále se podrobněji zaměříme na dotazování pomocí JDOQL a ukážeme si některé pokročilé možnosti tvorby dotazů.
Dedičnost persistentních tříd
Práce s objekty odvozených tříd není v JDO velký problém. Jediné, co je zapotřebí udělat, je zahrnout informaci o vzájemném vztahu dědičnosti mezi třídami do metadat každé odvozené třídy. Mějme třídu Osoba
známou již důvěrně z předchozích článků a vytvořme k ní odvozenou třídu Zamestnanec
:
public class Zamestnanec extends Osoba
{
/** Od kdy je u nás zaměstnán */
private Date zamestnanOd;
}
Metadata pro obě třídy budou vypadat následovně:
<package name=“demo“>
<class name=“Osoba“>
<field name=“jmeno“ persistence-modifier=“persistent“>
<extension vendor-name=“jpox“ key=“length“ value=“max 50″/>
</field>
…
</class>
<class name=“Zamestnanec“
persistence-capable-superclass=“Osoba“>
<field name=“zamestnanOd“ persistence-modifier=“persistent“/>
</class>
</package>
Z příkladu vidíme, že jediné, co je třeba při definici odvozené třídy udělat, je specifikovat nadřazenou třídu pomocí atributu persistence-capable-superclass
a nastavit persistenci nově definovaných vlastností (v našem případe vlastnosti zamestnanOd
).
Dědičnost tříd lze využít při čtení objektů z databáze. Jak jsme si již ukázali, například při získávání extentu třídy pomocí metody pm.getExtent()
lze zadat, zda se do extentu zahrnou i objekty všech odvozených tříd či nikoli. U dotazů pomocí JDOQL je situace obdobná.
Pokročilé dotazy nad objekty
V předchozích článcích jsme zmínili možnost využití jazyka JDOQL (JDO Query Language) pro výběr objektů z databáze na základě dotazu a probrali jsme základy tohoto jazyka a jeho integraci do JDO. Nyní se podíváme podrobněji na možnosti formulování složitějších dotazů s parametry a na řazení výsledků dotazu.
Protože jazyk JDOQL vychází z jazyka Java, dotaz v tomto jazyce má podobnou strukturu jako program v Javě. Skládá se z následujících částí:
- Import tříd
- Deklarace importovaných tříd z Javovských balíčků. Importování se použije pro kvalifikaci jmen tříd použitých v dotazu, aby nebylo nutné psát název balíčku u každé použité třídy.
- Deklarace parametrů
- Parametry reprezentují data dodávaná z vnějšku v okamžiku vykonání dotazu.
- Deklarace proměnných
- Jedná se o lokální proměnné v rámci dotazu.
- Nastavení kandidátské množiny
- Nastavení množiny objektů, nad kterou dotaz pracuje. Může se jednat buď o extent třídy nebo o libovolnou kolekci objektů.
- Nastavení třídy výsledných objektů
- Dotaz pracuje vždy s objekty jedné třídy. Pokud kandidátská množina obsahuje i objekty jiných třídy, jsou tyto objekty ignorovány a nejsou zahrnuty do výsledku dotazu.
- Nastavení filtru
- Filtr je logický výraz, který určuje, zda objekt bude součástí výsledku dotazu či nikoli.
- Nastavení řazení
- Výsledek dotazu může být seřazen podle zadaných kritérií.
Pro formulování dotazu je vždy nutno určit kandidátskou množinu (z čeho se budou objekty vybírat) a filtr (jak se budou vybírat). Ostatní části dotazu jsou volitelné. Výsledkem dotazu je vždy kolekce objektů (potenciálně prázdná), která obsahuje objekty z kandidátské množiny, které vyhovují filtru. Objekty ve výsledné kolekci mohou být libovolně seřazeny.
Jak jsme si již ukázali dříve, dotaz je reprezentován objektem implementujícím rozhraní javax.jdo.Query
, který získáme pomocí voláním metody pm.newQuery()
. Nastavení a spuštění dotazu pak již probíhá výhradně prostřednictvím tohoto objektu. Podívejme se na jednotlivé fáze podrobněji.
Kandidátská množina
Kandidátskou množinu tvoří buď extent třídy nebo libovolná kolekce objektů, v tom případě musíme ovšem specifikovat třídu objektů, se kterými pracujeme. V praxi jsou možné následující kombinace zadání kandidátské množiny:
- Zadáme pouze třídu objektů. Za kandidátskou množinu se bude považovat extent této třídy včetně odvozených tříd.
- Zadáme přímo předem vytvořený extent.
- Zadáme kolekci a třídu objektů. Kandidátskou množinu tvoří všechny objekty dané třídy obsažené v kolekci.
Máme-li objekt q
třídy Query
reprezentující nějaký dotaz, pak třída objektů, se kterou se pracuje, se nastavuje voláním q.setClass()
. Extent nebo kolekce se nastavuje pomocí q.setCandidates(Extent)
, respektive q.setCandidates(Collection)
. Tyto parametry je možno předat přímo metodě pm.newQuery
, která vytváří objekt dotazu. Existuje více variant této metody s různými z výše uvedených parametrů.
Filtr
Filtr může být zadán rovněž při vytváření objektu dotazu, nebo dodatečně voláním q.setFilter()
. Filtr je reprezentován řetězcem obsahujícím logický výraz, který je vyhodnocen pro každý objekt v kandidátské množině. Pokud je výsledek výrazu true
, je příslušný objekt zařazen do výsledku dotazu. Možné logické výrazy jsme již zmínili v předchozích článcích.
Dotazy s parametry
Důležitou vlastností JDOQL je možnost parametrizovat dotazy. Podobně jako u funkcí v Javě, parametry představují proměnné hodnoty dodané z vnějšku v okamžiku spuštění dotazu. Ukažme si parametry na praktickém příkladě. Mějme třídu Akce
:
import java.util.Date;
public class Akce
{
/** Název akce */
public String nazev;
/** Počáteční datum */
public Date datefrom;
/** Koncové datum */
public Date dateto;
}
Zkusme vytvořit funkci aktivniAkce()
, která vybere všechny právě probíhající akce. Musíme tedy zformulovat dotaz, který vybere všechny akce, jejichž začátek je před dnešním datem a konec po dnešním datu:
import java.util.*;
PersistenceManager pm; /* vytvoren drive */
public Collection aktivniAkce()
{
/* Vytvoříme dotaz, zadáme třídu objektů a filtr */
Query q = pm.newQuery(Akce.class,
„datefrom <= now && dateto >= now“);
/* Import třídy Date */
q.declareImports(„import java.util.Date“);
/* Deklarujeme parametr ‚now‘ */
q.declareParameters(„Date now“);
/* Zjistíme dnešní datum */
Date dnes = new Date();
/* Spustíme dotaz */
Collection result = (Collection) q.execute(dnes);
return result;
}
V deklarovaném filtru odpovídají hodnoty datefrom
a dateto
vlastnostem třídy Akce
, se kterou pracujeme. Hodnota now
je parametr deklarovaný níže pomocí volání q.declareParameters()
. Ve všech případech se jedná o hodnoty typu Date
. Konkrétní hodnotu parametru now
předáme až v okamžiku provedení dotazu jako parametr metody q.execute()
. Existují varianty této metody pro žádný až tři parametry, tímto způsobem lze tedy předat až tři parametry. Pořadí, v jakém se předávají, pak odpovídá pořadí jejich deklarace. Více parametrů lze předat pomocí mapy (objektu typu Map
) pomocí volání q.executeWithMap()
.
Řazení výsledků dotazu
Řazení výsledků zadáváme pomocí volání q.setOrdering()
před provedením dotazu. Parametrem je řetězec, který obsahuje jednu či více deklarací oddělených čárkami. Každá deklarace se skládá z názvu vlastnosti třídy, podle které se bude řadit, následované klíčovým slovem ascending
pro vzestupné řazení nebo descending
pro sestupné řazení. Chceme-li předchozí příklad upravit tak, aby byly získané akce seřazeny vzestupně podle data začátku a následně podle jména, přidáme před provedení dotazu následující volání:
q.setOrdering(„datefrom ascending, name ascending“);
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
-
AI v programování: Jak používat GitHub Copilot (část 1)
12. února 2024 -
Landing page: Jak vytvořit landing page s vysokým CTR
7. května 2024
Nejnovější
-
Jak rozšířit úložiště Macu za pětinovou cenu?
16. prosince 2024 -
Nové trendy v doménách pro osobní projekty – DIY, LIVING a LIFESTYLE
9. prosince 2024 -
Jak chránit webové stránky před Web/AI Scrapingem
27. listopadu 2024 -
Jaký monitor je nejlepší k novému Macu Mini?
25. listopadu 2024