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.

Žádný příspěvek v diskuzi

Odpovědět