Tvorba dotazů

Po té co jsme definovanou entitu i uložili do databáze, je na čase zabývat se tím co s ní dál. Určitě entity budeme potřebovat načítat, ale i mazat, či pracovat s jejich surovými daty. Při tom všem však již budeme potřebovat sestavovat dotazy.

Patrně jste již na nějaké dotazy narazili. Buď při zkoumání ukázkové aplikace, nebo v kapitole o vnějších relacích. A určitě vás trklo, že dotazy mají podobu pole. Je klidně možné, že u někoho se dostavit "WTF?!" efekt :-) Ale má to svou jasně danou logiku a je to nejlepší řešení. Hned si řekneme proč.

Dotazy = pole? Proč?!

Pokud má být ORM nezávislé na použitém typu backendu - tedy databáze, tak se nemůže v rámci dotazů spoléhat na žádný konkrétní SQL dialekt. To je evidentní.

Jaké jsou ale možnosti?

Jako první se nabízí nějaký univerzální SQL dialekt a ten parsovat a transformovat. Ale proč to hergot dělat? Není to rovnák na ohýbák? Vyvíjet (nebo integrogart) nějaký parser je spousta neproduktivní práce, spousta neproduktivního kódu o který je třeba se starat. Z hlediska nákladů to nemá ospravedlnění. Prostě parsovat SQL, aby na druhém konci bylo SQL a vynaložit na to prostředky (čas = peníze) nemá logiku a absolutně žádný přínos. Nehledě na to, že to znamená i režii strojového času během provozu aplikace.

Další možnost ... Co to udělat nějak objektově a poskládat dotazy formou volání metod a dotaz mít reprezentován objektovým modelem? Fajn, tak to ve skutečnosti v Jet DataModel je. Dotaz má ve skutečnosti opravdu svůj model a je reprezentován instancemi tříd. Když se podíváte do hlubin Jet DataModel, tak na to určitě narazíte. Ale je to nepoužitelné pro aplikace z reálného světa (i když to technicky použít lze). Proč? Protože velice často dotazy tvoříme, skládáme, sestavujeme. Například na základě toho jaký má uživatel filtr a na základě miliónů dalších aspektů. A pro takové použití je nějaké volání metod čehosi opravdu krajně neefektivní a nepřehledné.

Nechtěl jsem ani vyvíjet rovnák na ohýbák aby to bylo "doměle sexy". Pro mne je sexy to co je efektivní. A nechtěl jsem ani bolavou hlavu z objektového blázince, který by zrovna v tomto případě byl kontraproduktivní. Proto jsem zvolil tuto cestu a dotazy v Jet DataModel se formulují jako pole. Tedy například takto: $where = [];

if( 
$search ) {
    
$search '%' $search '%';

    
$where[] = [
        
'article_localized.title *'      => $search,
        
'OR',
        
'article_localized.text *'       => $search,
        
'OR',
        
'article_localized.annotation *' => $search,
    ];
}

if( 
$another_filter ) {
    if(
$where) {
        
$where[] = 'AND';
    }

    
$where[] = [
        
'article.id' => another_filter
    
];
}
//... ... ...

$articles = static::fetchInstances$where );

Základní princip

Jak je patrné z jednoduchého příkladu výše, tak dotaz kombinuje běžné a asociované pole.

Klíče pole tvoří referenci na příslušnou vlastnost entity. Reference je tvořena takto: nazev_entity.nazev_vlastnosti. Tedy právě zde je použit názvy entit určené definicí. Název entitu je názvem jakékoliv entity, která ovšem je ve vnitřní i vnější relaci.

O provázání tabulek se starat nemusíte. To udělá Jet DataModel automaticky na základě definic relací. Prostě definice určuje jak má fungovat provázanost a v dotazech tuto provázanost jednoduše používáte.

Název vlastnosti je jasný - přesně odpovídá názvu vlastnosti třídy entity (ne sloupečku v DB tabulce - ten se může jmenovat odlišně).

Vaší pozornosti jistě neunikl znak * za referencí. To je jeden z operátorů. Na operátory se koukneme později.

Hodnota prvku pole (zde tedy prvku dotazu) je hodnota, která se má vztahovat k danému prvku dotazu. Ale je třeba si říct, že hodnota může být i pole. Backend si s tím poradí a z pole udělá například známé ... AND article.id IN ( 5, 6, 99, 100) ...

Dále může následovat logický operátor 'OR', nebo 'AND'. A ty již nejsou asociované. Tedy logické operátory přidáváme do dotazu jako do běžného pole.

V neposlední řadě je třeba říct, že dotaz se může skládat z dalších dotazů. Lépe řečeno pole se může skládat z dalších polí, které tvoří logické podskupiny dotazu. Je to to samé, jako závorky () v SQL. Pro přehlednost takto: $where = [
    [
       
'entity_x.property_a' => 1,
       
'OR'
       'entity_x.property_b' 
=> 2
    
],
    
'AND',
    [
       
'entity_y.property_a' => 3,
       
'OR'
       'entity_y.property_b' 
=> 4
    
    
]
];

Operátory

A teď k těm operátorů, které mohou být za referencí. Píšu 'mohou', protože výchozí operátor = se uvádět nemusí, ale zároveň také operátor = nemusí znamenat = ve smyslu SQL, ale operátor IN, pokud je použito pole ... Ukažme si raději tabulku s přehledem všech operátorů.

Operátor Význam v SQL
=
(Nepovinný, výchozí - netřeba uvádět)
Pokud navázaná hodnota není polem, tak operátor představuje běžný operátor =
Pokud je navázaná hodnota pole, pak operátor představuje SQL IN( ... )
!=
Pokud navázaná hodnota není polem, tak operátor představuje běžný operátor <>
Pokud je navázaná hodnota pole, pak operátor představuje SQL NOT IN( ... )
* LIKE '...'
!* NOT LIKE '...'
> V SQL stejný význam
< V SQL stejný význam
>= V SQL stejný význam
<= V SQL stejný význam
Předchozí kapitola
Mazání
Další kapitola
Načítání