Rozhodl jsem se publikovat první technicky založený článek. Mapování objektů do relační databáze je pro dnešní objektové jazyky občas oříškem. Největší neplechu páchá asociace typu M:N. Ta není dnešními objektovými jazyky přímo podporována. V tomto článku přiblížím, jak úspěšně vysvětlit objektovým jazykům, že hvězdičky můžou svítit na obou stranách.
Cože to vlastně ta asociace typu M:N je? Každý se s ní už určitě setkal. Na diagramu 1 je zobrazen jednoduchý příklad. Učitel může vyučovat několik žáků z různých tříd a zároveň každý žák může být vyučován několika různými učiteli. Dokážu si představit, že obě analytické třídy budou nahrazeny návrhovými třídami a že hodnoty atributů budou uloženy ve dvou tabulkách relační databáze. Ve fázi analýzy je na tento diagram radost pohledět, jenže ve fázi návrhu už tak růžově nevypadá.
Podívejme se nyní do pozdější fáze analýzy, co se s naší školskou delegací stalo. Na diagramu 2 jsou vidět doplněné atributy a operace. Jen objasním, že operace zjistiSeznamZaku() vrací asociativní pole všech objektů typu Žák, které daný objekt typu Učitel vyučuje. Na opačné straně vrací operace zjistiSeznamUcitelu() asociativní pole všech objektů typu Učitel, které vyučují daný objekt typu Žák. Některé jazyky místo pole používají kolekce objektů, tím už se ale náš článek nezabývá. Ostatní atributy a operace popisovat nemusím, protože jsem zvolil opravdu jednoduchý příklad.
Přenesme se nyní mezi řádky nějakého skriptu, který vypisuje ke každému učiteli všechny vyučované žáky. Pokud by se databáze sestávala pouze ze dvou tabulek, jako je vidět v diagramu 3, budou nám stále chybět reference mezi jednotlivými objekty typů Učitel a Žák a náš skript, ať už bude sepsán jakkoli, náš cílený problém nevyřeší a nedokáže ke každému učiteli vypsat všechny jím vyučované žáky. Příklad tabulek je v MySQL.
Takže nám něco chybí. Pojďme se zbavit té ohyzdné asociace typu M:N a rozbijme ji na dvě asociace typu 1:M. Vložme mezi asociaci typu M:N jednu třídu navíc, kterou můžeme pojmenovat speciálním názvem například Výuka nebo jednoduše spojením názvů obou spojovaných tříd, tzn. UčitelŽák. Tato geniální třída bude sloužit jako pojítko mezi našimi třídami. Každá instance bude ukazovat právě na jeden objekt typu Učitel a právě na jeden objekt typu Žák. Jako celek jsem určil třídu Učitel z toho důvodu, že budeme vypisovat žáky, které učitel vyučuje. Objekty typu Učitel jsou tedy odpovědné za životní cyklusy objektů typu Výuka. Stejně tak bychom mohli třídu Výuka přiřadit třídě Žák. Výsledek je zobrazen na diagramu 4.
Na diagramu 5 jsou zobrazeny tabulky relační databáze, které jsou nyní propojené přes cicí klíče (foreign keys) tabulky Výuka.
(pozn. děkuji maartymu za upozornění komentářem, že EA umí modelovat databáze…)
Metoda zjistiSeznamZaku() nyní vybere z tabulky Výuka veškeré řádky, u kterých je idUcitele rovno id hledaného učitele. Metoda vytvoří pole objektů typu Žák, jejichž id se nachází v nalezených řádcích v tabulce Výuka. Toto pole nakonec vrátí. Již zmiňovaný skript nyní může pole projít a vypsat jméno a příjmení.
Tak jsme si osvětlili, jak se manuálně vypořádat s asociací typu M:N. Nad relačními databázemi dnes ale existují ORM nástroje, které se s asociací typu M:N vypořádají automaticky a programátor ani nepocítí, že se v databázi nachází ještě nějaká propojovací tabulka. Takový ORM nástroj pro PHP je například Doctrine, který je inspirován Hibernate pro Javu.
17.2.2009 20:09




