Takřka v každém evidenčním systému se vyskytují tzv. číselníky, někdy zvané také jako „kódovníky“, anglicky např. jako „Code List“. Jedná se o velmi jednoduché entity obsahující „kód + text“ (případně zkratka apod.), které pomocí odkazu přidělují daným prvkům vlastnosti jako hodnotu kódu. Většinou se tak děje ve scénáři výběrem od obsluhy. Každému kódu je přiřazen význam, což vyjadřuje obsah atributu text zobrazitelný obsluze. Jako příklady uveďme číselník barev, číselník typů bankovních služeb, číselník typů osob atd. Existuje několik možných analytických návrhů, jak tyto entity navrhnout a poté realizovat. V tomto článku si tyto možnosti uvedeme a také upozorníme na tzv. „posun meta“ (vysvětlení jevu nazvaném jako „posun meta“ viz kniha Analytické modelování v praxi zdarma zde).
Nechť chceme implementovat agendu číselníků „kód text“. Jako příklad zvolme dva číselníky: „Typ bankovních služeb“ (dále také „Typ BS“) a „Typ osob“ (dále také „Typ OS“).
Vyjmenujme si varianty řešení.
1. Varianta: Číselníky natvrdo (varianta „hard coded“)
Jako první variantu si uveďme způsob v posunu meta nejníže, tedy variantu „natvrdo“ („hard coded“). V tom případě vznikne řešení podle pravidla „co číselník, to analytická třída a následně tabulka“. Znamená, že s každým novým číselníkem se založí nová třída a poté i nová tabulka (tj. CREATE TABLE pro každý číselník se svým názvem).
Analytický model této varianty pak vypadá v našem příkladu takto:
Každá třída číselníku je multiinstanční, každá stojí samostatně a dává vzniknout itemům daného typu obsahujících kód a text.
2. Varianta: Posun meta s opětovnou použitelností
Zkusme si napsat jako příklad několik málo instancí ze tříd našich číselníků Typ BS a Typ OS. Současně si tyto třídy očíslujeme pro přehlednost takto:
Všimněme si, že „hlavičky“ číselníků (tj. neodsazené řádky) se chovají také jako prvky číselníku. Když si odmyslíme spodní prvky a ponecháme jen hlavičky, tak vznikne také číselník „kód text“:
1; TYP BS
2; TYP OS
Model tříd můžeme tedy navrhnout jako dvojúrovňový strom, analytický model je následující:
Všimněme si omezující podmínky, že se jedná o strom pouze se dvěma úrovněmi (tj. „hlavička“ a „itemy“).
Mapováním do relační databáze 1:1 dostáváme jednu tabulku, do které jsou umístěny prvky obou úrovní (tj. instance číselníků a itemy číselníků se vyskytují spolu v jedné tabulce), přičemž vazba mezi child a parent prvkem může být např. přes sloupec „autoincrement id“ a cizí klíč idParent takto:
Vrcholy stromu, tj. samotné číselníky (tj. „hlavičky“) nemají již nadřízeného Parenta a proto mají hodnotu vazebního klíče idParent = null.
Pozn. vazbu lze realizovat také přes kód a cizí klíč KódParenta. V tom případě má parent prvek KódParenta = 0. Hodnoty ve sloupci kód nejsou unikátní, proto vazba child itemu na vlastníka bude vyjádřena nejenom shodou klíčů kódů, ale také dodatečnou podmínkou, že kódParenta u Parenta = 0, tj. že vlastníkem itemu je „hlavička“. Tento způsob se mi však nejeví jako příliš vhodný, protože mohou nastat problémy, pokud se začne řešit problematika historie číselníku (např. kód itemu dané barvy aut se historicky změní, ale jedná se historicky o tutéž barvu).
Uvedená varianta reprezentuje oproti předešlému řešení „natvrdo“ ukázkový příklad posunu meta. Všimněme si, že to, co se ve variantě 1 (tj. varianta „hard coded“ = „co číselník, to třída“) vyskytovalo v názvech tříd (v našem příkladu Typ Osoby a Typ BS), tak to se ve druhé variantě umístilo do hodnot instancí. To již není na úrovni tříd, ale na úrovni instancí a hodnot, došlo tedy k posunu od tříd do instancí.
Tento rozdíl se projeví například v těchto dvou situacích:
a. Druhá varianta s posunem meta je dynamická v tom smyslu, že uživatel může dynamicky přidat nový číselník bez nutnosti měnit kód. Pokud bychom tuto funkcionalitu vyžadovali i v prvém řešení, museli bychom v běhu programu volat „CREATE TABLE“, což je vlastně meta-programování.
b. Chceme uživateli vypsat všechny možné použitelné číselníky (kódovníky) a on by si měl vybrat číselník. Ve variantě 2 s posunem meta se jedná o jednoduchý příkaz SELECT nad danou tabulkou s podmínkou pro cizí klíč idParent = null. V první variantě bychom se museli posunout do meta-prostoru, protože vypisujeme seznam tabulek, což by se dalo vyřešit například „pseudo-systémovou“ tabulkou, která by obsahovala seznam názvů tabulek a „imitovala“ by tak systémovou tabulku v meta-prostoru databáze.
3. Varianta: Posun meta, ale se dvěma třídami
Příklad b. uvedený v předešlém odstavci vede k možnému třetímu řešení, které je podobně jako varianta 2 posunem meta, ale nevyužívá opětovnou použitelnost na 100% (tj. „něco se v řešení opakuje“). V tomto případě se nepoužije jedna třída, ale dvě třídy: Jedna vyjadřuje samotné číselníky a druhá jejich itemy jako vlastněné prvky, vyjádřeno modelem tříd takto:
Omezující podmínku dvou úrovní již nemusíme nasazovat, je to již vlastnost modelu tříd jako takového, protože číselníky mají itemy a itemy již nemají žádné děti.
Při mapování do RDB vzniknou dvě tabulky, jedna pro seznam číselníků (umístíme do jedné tabulky) a itemy jako jejich děti (umístíme do tabulky druhé). Oproti předešlému řešení se opakuje struktura „kód text“, takže její obsloužení se bude programovat dvakrát pro obě třídy (což si myslím není až tak tragické).
Závěr první části
Máme zde před sebou tři řešení. Za svou dvacetiletou praxi jsem měl možnost spolupracovat se stovkami firem v ČR a SR, takže jsem se v praxi setkal se všemi třemi implementacemi.
Napsat komentář