MASARYKOVA UNIVERZITA FAKULTA INFORMATIKY

Objektovo-relačné mapovanie a jeho použitie na platforme .NET

DIPLOMOVÁ PRÁCA Tomáš Stach

Brno, 2013

i Prehlásenie

Prehlasujem, že táto diplomová práca je mojím autorským dielom, ktoré som vypracoval samostatne. Všetky zdroje, pramene a literatúru, ktoré som pri vypracovaní používal alebo z nich čerpal, v práci riadne citujem s uvedením úplného odkazu na príslušný zdroj.

Vedúci práce : RNDr. David Sehnal

ii Poďakovanie

Rád by som poďakoval vedúcemu práce RNDr. Davidovi Sehnalovi za jeho podporu a cenné pripomienky a svojim nadriadeným v zamestnaní za zhovievavosť. Poďakovanie si zaslúži aj moja rodina a priateľka za obrovskú dávku trpezlivosti.

iii Zhrnutie

Cieľom tejto práce je zoznámiť čitateľa s objektovo-relačným mapovaním na platforme .NET. Po predstavení relačného a objektového modelovania nasleduje popis problematiky objektovo-relačného mapovania, jeho výhodami, nevýhodami a rozdielmi jeho použitia v programoch voči klasickému dopytovaniu pomocou SQL, resp. využitiu inej ako relačnej databázy. Následne sú niektoré konkrétne najčastejšie používané nástroje predstavené detailne a je porovnaný ich výkon v niekoľkých testoch. Súčasťou práce je testovacia aplikácia, ktorá bola použitá pri porovnávaní a testovaní výkonu jednotlivých nástrojov.

iv Kľúčové slová

Relačná databáza, NoSQL databáza, objektovo-relačné mapovanie, návrhové vzory, platforma .NET, LINQ, Entity Framework

v Obsah

Kapitola 1 Úvod 1 1.1 Formulácia práce ...... 1 1.2 Delenie práce ...... 1 Kapitola 2 Databázy a relačné modelovanie 2 2.1 Pred-relačné databázy ...... 2 2.2 Relačné databázy ...... 3 2.3 Post-relačné databázy ...... 10 Kapitola 3 Objektové modelovanie 14 3.1 Vlastnosti objektu ...... 14 3.2 Modelovanie s objektami ...... 15 3.3 Vzťahy medzi objektami ...... 16 Kapitola 4 Objektovo-relačné mapovanie 19 4.1 Impedance mismatch ...... 19 4.2 Mapovanie objektov na relácie ...... 21 4.3 Princípy fungovania ORM ...... 25 4.4 Výhody použitia ORM ...... 41 4.5 Nevýhody použitia ORM ...... 42 Kapitola 5 Platforma .NET a použité databázy 43 5.1 Platforma .NET ...... 43 5.2 Microsoft SQL Server ...... 50 5.3 RavenDB ...... 51 Kapitola 6 Prehľad ORM nástrojov 52 6.1 Aktívne projekty...... 52 6.2 Neaktívne projekty ...... 56 Kapitola 7 Vybrané ORM nástroje 58 7.1 Entity Framework ...... 58 7.2 LINQ to SQL ...... 66 7.3 NHibernate ...... 70 7.4 LLBLGen Pro ...... 77 Kapitola 8 Testovanie 83 8.1 Testovacia aplikácia ...... 83 8.2 Prostredie ...... 84 8.3 Testy ...... 85 8.4 Vyhodnotenie ...... 95

vi Kapitola 9 Záver 97 Literatúra 99 Prílohy 105 Príloha A: Diagramy databáz ...... 105 Príloha B: Zdrojové kódy testovacích dopytov ...... 107 Príloha C: Elektronické prílohy ...... 131 Príloha D: Namerané výsledky testov ...... 131

vii Kapitola 1 Úvod

Väčšina netriviálnych aplikácií potrebuje nejakým spôsobom uchovávať svoje dáta, v drvivej väčšine prípadov ide o databázu. Už desaťročia sú v praxi najviac nasadzované relačné databázy založené na relačnom modeli. Medzi momentálne najpopulárnejšie programovacie jazyky patrí hlavne Java a C#. [1] Tieto objektovo orientované jazyky sú dlhodobo zaužívané a primárne využívané na vývoj podnikového softvéru a webových aplikácií. Pri ich vývoji treba venovať čas prevodu zložitých dátových typov na jednoduché skalárne typy uchovávané v relačnej databáze. Tento prevod môže programátor vykonať ručne, alebo môže využiť nástroj objektovo- relačné mapovanie, ktorý umožňuje komplexne vyriešiť nesúlad medzi objektovým a relačným modelom. Je nutné určiť mapovanie tried na jednotlivé tabuľky, resp. mapovanie atribútov objektu na stĺpce tabuliek. Následne je programátorovi dovolené pracovať priamo s objektovým modelom namiesto relačnej databázy. Takáto práca s objektami je omnoho pohodlnejšia a efektívnejšia ako práca s navzájom prepojenými riadkami dát. 1.1 Formulácia práce

Text práce je číslovaný a štruktúrovaný obvyklým spôsobom. Prvý výskyt cudzieho, alebo odborného termínu je označený kurzívou. Popisovaná problematika obsahuje množstvo anglických termínov, ktoré sú v prípade možného slovenského ekvivalentu preložené. Originálny anglický názov je uvedený v zátvorke. Niektoré výrazy nie sú lokalizované z dôvodu neexistujúceho (MapReduce ), alebo nevhodného (Session ) prekladu. Ukážky zdrojových kódov a názvy tried, či metód sú odlíšené iným fontom textu. 1.2 Delenie práce

Kapitola 2 popisuje rozdelenie databáz. U relačných sú vysvetlené špecifiká relačného modelovania a problematiky s ním spojenej, záver kapitoly sa týka moderných databázových systémov (NoSQL ). Nasledujúca kapitola 3 predstavuje objekty používané v objektovo orientovanom programovaní. Po zoznámení čitateľa s relačným a objektovým prístupom práca pokračuje kapitolou 4, ktorá predstavuje objektovo-relačné mapovanie, technológiu umožňujúcu prepojiť oba spomínané svety. Sú spomenuté základné pojmy problematiky a návrhové vzory využité pri tvorbe nástrojov spadajúcich do tejto kategórie. V kapitole 5 je popis základných technológii použitých v praktickej časti práce. Kapitoly 6 a 7 sa zaoberajú aktuálnou situáciou objektovo-relačného mapovania na platforme .NET. Niektoré nástroje predstavené v týchto kapitolách sú otestované v aplikácii, ktorá je spolu so spôsobom testovania a výsledkami popísaná v kapitole 8. Posledná kapitola 9 obsahuje záver celej problematiky a ponúka názor autora práce.

1 Kapitola 2 Databázy a relačné modelovanie

Pod pojmom databáza si aj človek bez informatického vzdelania dokáže predstaviť skupinu údajov, ktoré sú istým spôsobom štruktúrované. Typickým príkladom môže byť napríklad databáza telefónnych čísiel, či liekov. V oblasti počítačov pojem databáza vyjadruje v princípe to isté: štruktúrovanú kolekciu (množinu) usporiadaných dát využívanú k ukladaniu a získavaniu informácií. Prvé databázové systémy sa objavili pred viac ako piatimi dekádami a za túto dobu prešli veľmi zaujímavým vývojom. Momentálne existuje značné množstvo druhov, najpoužívanejším je jednoznačne relačný typ, ktorému sekundujú databázy typu NoSQL. Táto kapitola uvedie čitateľa do problematiky databáz a podrobnejšie mu vysvetlí princípy na ktorých fungujú aktuálne tieto dva najpoužívanejšie typy. Ďalej sú vysvetlené základy relačného modelovania, ktorých pochopenie je dôležité pri štúdiu objektovo- relačného mapovania v kapitole 4. Dnes sú pokladané za databázový „štandard“ relačné databázy, ktoré sú najviac rozšírené, dostupné, majú za sebou veľmi dlhý vývoj a hlavne sú plne dostačujúce. Vo väčšine prípadov ide o prvý typ databázy s ktorým začínajúci vývojár príde do styku pri bežnej praxi, alebo v škole. Existuje však mnoho iných typov databáz, ktoré nespadajú do kategórie relačných a môžeme ich z časového hľadiska rozdeliť do dvoch skupín: na tie, ktoré vznikli skôr a na tie, ktoré vznikli neskôr, teda na pred-relačné a post-relačné databázy. Pojmy databáza a databázový systém sa často zamieňajú. Databázový systém, resp. Systém riadenia báze dát ( SRBD 1 ) je kolekcia softvéru, ktorá užívateľom umožňuje získavať, vytvárať a modifikovať informácie z databázy. Databáza je len samotný súbor dát. 2.1 Pred-relačné databázy

Prvé databázy vznikli v 60-tych rokoch minulého storočia. Historicky prvou komerčnou bola databáza IMS ( Information Management System ) hierarchického typu od spoločnosti IBM, ukladajúca dáta v stromovej štruktúre. Základnými operáciami bolo vyhľadávanie všetkých potomkov alebo rodiča daného záznamu. Dnes podobnú štruktúru uchovania dát využíva značkovací jazyk XML 2. Nasledovníkom a rozšírením sa stali sieťové databázy zastupované systémom IDMS (Integrated Database Management System ). Na rozdiel od hierarchického modelu, kde každý záznam mal práve jedného rodiča, pri sieťovom modeli môže byť rodičov viac. Toto vylepšenie síce prináša omnoho efektívnejšie a elegantnejšie dopytovanie, ale údržba odkazov medzi uzlami dát je zložitá a náročná. [2], [3]

1 SRBD je z angl. DMBS ( Data Base Management System ). 2 XML ( Extensible Markup Language ) umožňuje popis štruktúry dokumentu, alebo dát. 2 KAPITOLA 2: DATABÁZY A RELAČNÉ MODELOVANIE 2.2 Relačné databázy

Vyvinuli sa z predchádzajúcich typov databáz založených na odkazoch medzi jednotlivými uzlami. Základnú myšlienku relačného modelu dát priniesol v roku 1970 pracovník IBM Edgar Frank Codd v článku s titulom „A Relational Model of Data for Large Shared Data Banks “ [4], kde navrhol nahradiť hierarchický a sieťový model novým modelom založenom na vzťahoch medzi tabuľkami dát. Coddova revolučná myšlienka dokázala prekonať hlavné obmedzenie databáz používaných v tej dobe, ktorým bola nutná znalosť fyzického usporiadania dát. Jeho relačný model popisuje dáta v ich prirodzenom usporiadaní bez akéhokoľvek prekrývania sa s pomocnými dátami určenými počítačovému systému. V článku Codd predstavuje a popisuje koncepty tabuliek, stĺpcov, primárnych a sekundárnych kľúčov, dokonca navrhuje princíp normálnej formy a predstavuje rôzne operácie na množinách vrátane operácie spájania tabuliek ( Join ). [4] Toto bola prvá zmienka o tabuľkách, dopytovacom jazyku a hlavne o relačných databázach, ktoré sa neskôr stali najrozšírenejším spôsobom ukladania dát v počítačových systémoch. [5]

2.2.1 Dvanásť pravidiel relačnej databázy Codd neskôr publikoval dvanásť pravidiel (v skutočnosti trinásť, číslované sú od nuly), ktoré musí databáza spĺňať aby mohla byť nazvaná relačnou: [6] 0. Základné pravidlo ( Foundation Rule ): Relačná databáza musí pri spracovaní dát využívať len svoje relačné schopnosti. 1. Pravidlo informácií (Information Rule ): Všetky informácie v databáze sú reprezentované len ako hodnoty v tabuľkách. 2. Pravidlo garantovaného prístupu ( Guaranteed Access Rule ): Všetky dáta v databáze sú logicky prístupné kombináciou názvu tabuľky, hodnoty primárneho kľúča a názvu stĺpca. 3. Systematické zachádzanie s hodnotami typu null (Systematic Treatment of Null Values ): Hodnotou typu null (inou ako prázdny textový reťazec) je reprezentovaná chýbajúca informácia akéhokoľvek dátového typu. 4. Dynamický on-line katalóg založený na relačnom modeli (Dynamic On-line Catalog Based on the Relational Model ): Popis databáze je logicky reprezentovaný rovnako ako dáta, takže užívatelia s oprávnením môžu využiť rovnaký dopytovací jazyk, aký používajú pri práci s bežnými dátami. 5. Pravidlo súhrnného dátového pod-jazyka (Comprehensive Data Sublanguage Rule ): Relačný systém môže podporovať viacero jazykov. Vždy však musí jestvovať najmenej jeden jazyk s dobre definovanou syntaxou podporujúcou definovanie dát, definovanie pohľadov, manipuláciu s dátami, integritu obmedzení, oprávnenia a transakcie.

3 KAPITOLA 2: DATABÁZY A RELAČNÉ MODELOVANIE 6. Pravidlo aktualizácie pohľadu ( View Updating Rule ): Každý teoreticky aktualizovateľný pohľad musí byť systémom naozaj aktualizovateľný. 7. Vysokoúrovňové vkladanie, zmeny a mazanie ( High-level Insert, Update, and Delete ): Schopnosť databáze zachovávať relačné pravidlá nielen pri dopytovaní, ale aj pri vkladaní, zmene a mazaní dát. 8. Nezávislosť fyzických dát ( Physical Data Independence ): Aplikačná vrstva a spôsob akým sú dáta používané sú nezávislé od spôsobu uloženia dát na fyzickej vrstve. 9. Nezávislosť logických dát ( Logical Data Independence ): Zmena na aplikačnej vrstve nevyžaduje zmenu vo fyzickom uložení dát. 10. Pravidlo nezávislosti integrity ( Integrity Independence Rule ): Obmedzenia integrity musia byť definované v pod-jazyku databázy, uložené v jej katalógu a nie v aplikácii. 11. Pravidlo nezávislosti rozmiestnenia ( Distribution Independance Rule ): Rozmiestnenie časti databáze na rôzne miesta by malo byť užívateľom neviditeľné. 12. Pravidlo nerozvrátenia (Nonsubversion Rule ): Databázový jazyk nízkej úrovne nemôže obísť obmedzenia integrity vyjadrené jazykom vyššej úrovne. [5] V súčasnosti používané relačné databázy síce klasifikujeme ako relačné, v skutočnosti niektoré body nespĺňajú. Najčastejšie nesplnenými pravidlami sú tretie (zachádzanie s hodnotami typu null), šieste (aktualizácie pohľadov) a deviate pravidlo (nezávislosť logických dát). [7]

2.2.2 Typickí predstavitelia Z hľadiska použitia a umiestnenia môžeme relačné databázy rozdeliť do dvoch skupín:

Desktopové databázy Ide o jednoduché, lokálne databázové systémy bežiace na pracovných staniciach. Medzi najrozšírenejšie patria Microsoft Access a Filemaker Pro. Sú určené pre lokálne ukladanie dát, v obmedzenom rozsahu môžu byť využité vo viac-užívateľskom prostredí. [8]

Serverové databázy Databázový systém beží typicky na serveri a je určený pre obsluhu viacerých užívateľov naraz. Medzi základné vlastnosti patrí vysoký výkon a dostupnosť. Najrozšírenejšou databázou tohoto typu je SQLite s licenciou typu Public domain. Paradoxne je jej hlavným využitím funkcia lokálnej zabudovanej databázy pre webové prehliadače (Mozilla Firefox, Google Chrome), antivírové programy (McAfee Antivirus), mobilné telefóny (Apple iPhone, platforma Google Android) a mnoho ďalších. Využíva sa tiež ako serverová databáza pre internetové stránky menšieho rozsahu (do stotisíc návštev denne). Je to najviac používaná relačná databáza na svete. [9] Do skupiny najrozšírenejších relačných databáz patrí aj MySQL s licenciou GNU GPL a komerčné verzie Microsoft SQL Server (sekcia 5.2) a Oracle Database.

4 KAPITOLA 2: DATABÁZY A RELAČNÉ MODELOVANIE Mimo dlhotrvajúci vývoj, vysokú stabilitu a výkonnosť je hlavnou devízou relačných databáz hlavne matematický aparát relačnej algebry na ktorom sú postavené a kvôli ktorému sú považované za štandard.

2.2.3 Relačná algebra a relačný model Relačnú algebru dostal do širšieho povedomia už spomenutý E. F. Codd. Operandami relačnej algebry sú relácie a ich výsledkom sú tiež relácie. Zjednodušene povedané je možné reláciu reprezentovať dvojrozmernou tabuľkou, ktorá je tvorená riadkami a stĺpcami. Množina riadkov vyjadruje reláciu, jej prvky tvoria usporiadané n-tice. Každý zo stĺpcov musí mať v rámci tabuľky unikátny názov – atribút, ktorý v tabuľke vyjadruje názov stĺpca a patrí určitej doméne. Doména atribútu vyjadruje obor hodnôt, čiže dátový typ. Hodnoty riadkov v príslušných stĺpcoch musia byť tiež tohoto typu.

Relácia Schéma (definícia) relácie sa skladá z troch základných častí: názov relácie, názvy atribútov a špecifikácia jednotlivých domén. Neobsahuje dáta, príklad schémy relácie: Predmety(Kód predmetu:string, Názov predmetu:string, Počet kreditov:integer) Až po pridaní riadkov vzniká inštancia relácie tak, ako ukazuje tabuľka 2.1. Kód Počet Názov predmetu predmetu kreditov PA116 Domain Understanding and Modeling 6 PA179 Project Management and Service Lifecycle 6 PV207 Business Process Management 5 Tabuľka 2.1: Inštancia relácie Predmety Z matematického hľadiska je relácia vzťah medzi skupinou prvkov jednej alebo viacerých množín:

„Nech A, B sú ľubovoľné množiny. Reláciou medzi množinami A, B je ľubovoľná podmnožina karteziánskeho súčinu A × B. Ak je ρ ⊆ A × B relácia a ak sú a ∈ A, b ∈ B prvky také, že (a, b) ∈ ρ, potom hovoríme, že prvok a je v relácii ρ s prvkom b a stručne zapisujeme a ρ b. Ekvivalentným zápisom je (a, b) ∈ ρ.“

Podľa počtu množín sa relácie delia na unárne, binárne, ternárne a n-árne. V relačnej algebre reláciu chápeme ako určitý predikát spravodlivosti Codd pôvodne v roku 1970 definoval nasledujúcich päť základných operácií nad reláciami. V zátvorke sa nachádzajú pôvodné originálne názvy tak, ako sú uvedené v jeho článku [4]. 1. Selekcia (Permutation ) 2. Projekcia ( Projection ) 3. Karteziánsky súčin (Join )

5 KAPITOLA 2: DATABÁZY A RELAČNÉ MODELOVANIE 4. Zjednotenie (Composition ) 5. Rozdiel množín (Restriction ) Neskôr k nim bola pridaná posledná, šiesta operácia premenovanie ( Rename ), ktorú požadovali tvorcovia jazyka ISBL. Všetky ďalšie operácie sa dajú odvodiť z uvedených základných. Je dôležité spomenúť, že žiadna z operácií nemení relácie, ktoré figurujú v pozícii operandu. Návratové hodnoty operácií sú „nové“ relácie. Nasledujúce tabuľky 2.2, 2.3 a 2.4 označujú tri relácie, ktoré budú použité pre bližšie vysvetlenie každej zo základných operácií:

A B C C D E A B C

a1 b1 c1 c1 d1 e1 a3 b3 c3

a2 b2 c2 c2 d2 e2 a4 b4 c4

a3 b3 c3 Tabuľka 2.3: Relácia U Tabuľka 2.4: Relácia V Tabuľka 2.2: Relácia T

Projekcia Symbolom tejto unárnej operácie je „Π“ (pí). Projekcia z tabuľky vyberie len určité

špecifikované stĺpce, takže hodnotou výrazu Π,,…, (R) je relácia, ktorá obsahuje len stĺpce A,A,…,A z R . Napríklad výsledkom výrazu Π,(T) je relácia znázornená v tabuľke 2.5. A C

a1 c1

a2 c2

a3 c3 Tabuľka 2.5: Výsledok projekcie

Selekcia Symbolom tejto unárnej operácie je „σ“ (sigma). Selekcia vyberie podmnožinu záznamov v relácii podľa výberovej podmienky: σ()(R) = X | R(X) ∧ C(X)} . Výsledkom výrazu

σ(T) je relácia znázornená v tabuľke 2.6. A B C

a1 b1 c1 Tabuľka 2.6: Výsledok selekcie

Karteziánsky súčin Symbolom tejto binárnej operácie je „ד. Karteziánsky súčin je v relačnej algebre definovaný odlišne od teórie množín, kde vytvára množinu dvojíc. V relačnej algebre karteziánsky súčin spáruje každý riadok prvej tabuľky s každým riadkom tabuľky druhej a vytvára tak n-tice, kde n je súčtom atribútov oboch relácií:

× = , … , , , … , | = (, … , ) ∈ ∧ = (, … , ) ∈ }.

6 KAPITOLA 2: DATABÁZY A RELAČNÉ MODELOVANIE Výsledkom karteziánskeho súčinu T × U je relácia v tabuľke 2.7. Oba operandy obsahujú atribút s rovnakým menom (C), vo výslednej relácii sú nové atribúty premenované podľa relácie z ktorej pôvodne pochádzajú. A B T.C U.C D E

a1 b1 c1 c1 d1 e1

a1 b1 c1 c2 d2 e2

a2 b2 c2 c1 d1 e1

a2 b2 c2 c2 d2 e2

a3 b3 c3 c1 d1 e1

a3 b3 c3 c2 d2 e2 Tabuľka 2.7: Výsledok karteziánskeho súčinu

Zjednotenie Symbolom tejto binárnej operácie je „∪“. Zjednotenie vyberie všetky n-tice zo vstupných relácií a vytvorí novú reláciu. Musí byť zaručená kompatibilita, teda obe relácie musia mať rovnaký počet stĺpcov rovnakého typu. ∪ S = x ∈ X | x ∈ ∨ ∈ . Výsledok zjednotenia ∪ V predstavuje tabuľka 2.8. A B C

a1 b1 c1

a2 b2 c2

a3 b3 c3

a3 b3 c3

a4 b4 c4 Tabuľka 2.8: Výsledok zjednotenia

Rozdiel Symbolom tejto binárnej operácie je „–“. Operácia vykonáva rozdiel medzi oboma reláciami, teda − = ∈ | ∉ }. Výsledkom rozdielu − je relácia znázornená v tabuľke 2.9. A B C

a1 b1 c1

a2 b2 c2 Tabuľka 2.9: Výsledok rozdielu

Premenovanie Symbolom tejto unárnej operácie je „“ (ró). Operácia premenuje názov relácie alebo atribútu na nové hodnoty. Výsledok premenovania ρ(,,)() je v tabuľke 2.10. Je možné premenovať len názov relácie bez zmeny názvov atribútov ( ρ()) alebo premenovať atribúty a zachovať názov relácie (ρ(,,)()). Táto operácia sa využíva k pomenovaniu

7 KAPITOLA 2: DATABÁZY A RELAČNÉ MODELOVANIE relácií, ktoré vznikajú aplikovaním operácií relačnej algebry na relácie s menom, na tabuľky. X Y Z

a1 b1 c1

a2 b2 c2

a3 b3 c3 Tabuľka 2.10: Relácia T ako výsledok premenovania [10]

Rozšírené operácie Existuje množstvo rozšírených operácií relačnej algebry, ktoré je možné definovať pomocou operácií základných. Napr. operáciu prirodzené spojenie ( natural join , symbol je „ ⋈“ ) je možné definovať pomocou selekcie a karteziánskeho súčinu: ⋈.. = ..( × ). Operácia spojenie sa vyskytuje v mnohých variantoch 3. Medzi ďalšie rozšírené operácie patrí napr. rozdiel, alebo prienik. Popis rozšírených operácií je nad rámec tejto práce, viac informácií sa dá nájsť v príslušnej literatúre, napr. [11], alebo [12].

Agregačné funkcie Tieto operácie ďalej rozširujú vyjadrovaciu schopnosť relačnej algebry, nie je možné ich vyjadriť pomocou štandardných základných operácií. Patria sem: • Operácia súčet ( sum ) • Operácia priemer ( average ) • Operácia minimum ( min ) • Operácia maximum ( max ) • Operácia počet ( count ) Relačná algebra má význam pri dopytovaní dát z DBMS. Výraz jazyka SQL 4 je možné transformovať na ekvivalentnú postupnosť priradení, ktorá sa volá logický plán. Tento plán sa dá jednoducho namapovať do fyzických operátorov konkrétneho DBMS. Takto vzniká fyzický plán výpočtu dopytu. Znalosť relačnej algebry vedie k lepšiemu pochopeniu DBMS pri vykonávaní SQL dopytu. [15]

Relačný model Modelovanie je nástroj slúžiaci pri vývoji softvérových systémov, umožňuje zjednodušene vyjadriť komplikovaný reálny systém zredukovaním jeho zložitosti.

3 Varianty operácie join sú napr.: inner/outer join, full outer join, left/right outer join, anti join, semi join, equi join, non-equi join. 4 SQL je štandardizovaný dopytovací jazyk nad relačnými databázami. Jeho popis je nad rámec tejto práce, viac informácií môže čitateľ nájsť v knihách, napr. [13]. 8 KAPITOLA 2: DATABÁZY A RELAČNÉ MODELOVANIE Relačné modely vylepšujú obmedzenia hierarchických štruktúr (viď sekcia 2.1), ku každej tabuľke môže byť pristupované priamo, bez nutnosti pristupovať k nadradeným objektom. [14] Z relačného systému je teda možné získať akékoľvek dáta, ak je známe meno relácie (tabuľky), primárny kľúč (identifikácia riadku) a meno atribútu (stĺpec).

Kľúče V relačných modeloch sa vyskytujú dva typy kľúčov: • Primárny kľúč (PK 5) je množina atribútov relácie, ktorej hodnoty sú unikátne. Je možné použiť aj kombináciu niekoľkých atribútov, vtedy musí byť unikátna ich kombinácia. Najčastejšie sú PK implementované pomocou sekvencií, ktoré sú unikátne pre každú reláciu. Je možné implementovať sekvenciu spoločnú pre viac relácií (tabuliek), táto funkcionalita sa používa pri modelovaní dedičnosti, viď podsekcia 3.2.1. Medzi nutné podmienky, ktoré musí PK spĺňať teda patrí jedinečná hodnota, ktorá nikdy nesmie byť typu null. Počas životnosti relácie sa táto hodnota nemení. • Cudzí kľúč (FK 6 ) je používaný na logické prepojenie jednotlivých relácií. Ide o atribúty relácií, ktoré ako svoju hodnotu používajú hodnotu iného atribútu inej relácie, najčastejšie primárneho kľúča. V prípade použitia cudzích kľúčov vzniká spájanie relácií, ktoré môže byť určitej násobnosti.

Násobnosť relácií Dve rôzne relácie sa môžu v systéme nachádzať samostatne (bez akejkoľvek spojitosti), ale aj s určitým vzťahom medzi sebou. Nasledujúci text používa výrazy ako tabuľka a riadok, tieto sú ekvivalentné výrazom relácia a n-tica v relácii. • Vzťah 1:1: Každý riadok v prvej tabuľke ma vzťah s najviac jedným riadkom tabuľky druhej a naopak. • Vzťah 1:N: Každý riadok v prvej tabuľke má vzťah s niekoľkými riadkami tabuľky druhej, naopak tento vzťah neplatí. Každý riadok z druhej tabuľky má vzťah najviac s jedným riadkom prvej tabuľky. • Vzťah M:N: Každý riadok v prvej tabuľke má vzťah s niekoľkými riadkami tabuľky druhej a naopak. Pre tento prípad je nutné použiť tretiu tabuľku. Na záver treba pripomenúť dôležitý fakt: Relačné databázy neukladajú relácie medzi entitami, ukladajú relácie medzi základnými dátovými typmi (text, čísla). Správu relácií medzi entitami nemá relačná databáza na starosti.

5 Z angl. Primary Key 6 Z angl. Foreign Key. 9 KAPITOLA 2: DATABÁZY A RELAČNÉ MODELOVANIE 2.3 Post-relačné databázy

Popularita relačného modelu dát v databázach od 80-tych rokov neustále stúpala, zároveň sa však objavili požiadavky, ktoré takéto systémy nedokázali plne uspokojiť. Patrila medzi ne podpora ukladania objektov do databáz.

2.3.1 Objektové databázy Myšlienky ukladať dáta v objektoch sa objavili s príchodom objektovo orientovaného programovania, väčšie rozšírenie takýchto databáz nastalo až začiatkom 90-tych rokov, keď vznikol objektový štandard ODMG 1.0 a objavili sa produkty firiem Gemstone Systems (GemStone), alebo Versant Corporation (FastObjects, Versant Object Database, DB4O). Posledná verzia štandardu ODMG 3.0 je z roku 2000. Objekty sú zapisované v jazyku ODL ( Object Definition Language ) a dopytované pomocou OQL ( Object Query Language ), tento jazyk však vďaka svojej zložitosti nebol kompletne implementovaný. [16] Hlavný rozdiel od relačných databáz je v pohľade na dáta. Relačné štruktúry vznikli z dôvodu nevyhovujúceho hierarchického usporiadania, objektové databázy však trpia rovnakými problémami. Využívajú síce základné rysy OOP a ich najväčšou výhodou je zvyšovanie produktivity vývoja, lebo programátor pracuje so štruktúrami prepojených objektov. Kvôli rozdielnemu prístupu k dátam v objektových jazykoch (sú uložené hierarchicky) a v relačných databázach (sú uložené v tabuľkách), ktorý sa nazýva ako Impedance Mismatch panoval v 90-tych rokoch minulého storočia názor, že relačné databázy zaniknú a budú nahradené práve databázami objektovými. Dáta v podnikoch sú však v praxi často používané a zdieľané naprieč rôznymi systémami, zobrazované v reportoch a to je oblasť, kde objektové databázy výrazne strácajú a kde je relačné usporiadanie ideálne. Tiež vďaka vyspelosti relačného modelu a jednotnej štandardizácii sa objektové databázy na trhu moc neujali. [17]

2.3.2 Objektovo relačné databázy Vznikli na základoch relačných systémov a ponúkajú možnosť definície vlastných dátových typov a metód. Prvýkrát sa objektové prvky v relačných databázach objavili s príchodom revízie SQL:1999, rovnako bolo možné definovať aj objemovo náročnejšie dátové typy (Char Large Objects na texty, Binary Large Objects na binárne dáta). V súčasnosti významné relačné databázové systémy majú črty objektovo relačných systémov, napr. Oracle, SQL Server. Tieto systémy sú používané na úkor čisto objektových práve z dôvodu relačných základov, na ktorých sú vybudované. Objektovo relačné databázy teda kombinujú výhody objektových a relačných databázových systémov. [12]

10 KAPITOLA 2: DATABÁZY A RELAČNÉ MODELOVANIE 2.3.3 NoSQL databázy NoSQL 7 znamená Not only SQL a nejde o typ databáz s presnou definíciou a charakteristikou. Na trhu sa objavili s rozvojom rozsiahlych webových stránok začiatkom 21. storočia, ktoré nemohli fungovať s klasickými relačnými databázami dostatočne efektívne (napr. google.com). Tieto databázy sú vhodné na masívne horizontálne škálovanie, keď je jednoduchšie a lacnejšie systém distribuovať medzi veľkým množstvom malých uzlov na úkor centralizácie. Často ide o open-source projekty, ktoré nutne nepotrebujú SQL ako svoj dopytovací jazyk. Ďalšou charakteristickou vlastnosťou je absencia relačného modelu a pevnej schémy dát. Je možné pridávať nové záznamy bez nutnosti vopred definovať ich štruktúru. [17] NoSQL databázy je možné rozdeliť do niekoľkých kategórií. Ich charakteristické vlastnosti a kompromisy sa dajú vyjadriť CAP teorémou.

Databázy typu kľúč-hodnota Dáta sú uložené vo veľkej hašovacej 8 tabuľke, kde je každý záznam tvorený unikátnym kľúčom a ľubovoľne štruktúrovanou hodnotou, je možné vyhľadávať len podľa kľúčov. Takýto dátový model je jednoduchý a vhodný pre zápis a čítanie veľkého množstva nekomplexných dát. Excelujú v horizontálnom škálovaní. Medzi nevýhody patrí mierne obmedzená funkcionalita a nevhodnosť na komplexné dáta. Významné projekty sú MemcacheDB, Redis, BerkeleyDB.

Dokumentové databázy Ukladajú dáta v kolekciách dokumentov. Dokument je štruktúrovaný objekt s unikátnym identifikátorom obsahujúci množinu dvojíc kľúč a hodnota, kde prvky hodnôt môžu byť skalárny typ, iný dokument, alebo pole hodnôt. Najčastejšie sú dáta uložené vo formátoch JSON 9 alebo XML. Nemajú schému dát pevnú, ale implicitnú. To znamená, že je nutné vedieť ako sú jednotlivé prvky hodnôt pomenované. Je tenká hranica medzi rozdelením databáz na dokumentové a typu kľúč-hodnota. Dokument môže byť charakterizovaný nejakým ID, ktorá sa chová ako kľúč a zvyšok dokumentu je prislúchajúca hodnota. Na druhú stranu, hodnota môže byť reprezentovaná formou metadát, ktoré sa môžu javiť ako dokument. Hlavným znakom je, že databázy typu kľúč-hodnota a dokumentové sú silne agregačne orientované, teda operácia agregácie je najčastejším spôsobom ako získať z databázy dáta. U dokumentových býva agregácia vykonaná podľa nejakej hodnoty z vnútornej štruktúry dokumentu, u typu kľúč-hodnota sa agregácia vykonáva podľa kľúča. Agregátom sa

7 Prvýkrát sa tento termín objavil v 90-tych rokoch v názve databázy Strozzi NoSQL od Carla Strozziho, ktorá nesúvisela s NoSQL dnešnými databázami. Rozšírenie totoho termínu nastalo až v roku 2009 po konferencii Johana Oskarssona v San Franciscu. 8 Z angl. hash , je to prevod dát na relatívne malé číslo. 9 JSON (JavaScript Object Notation) je štandard pre zápis dát, ktorý je čitateľný človekom. 11 KAPITOLA 2: DATABÁZY A RELAČNÉ MODELOVANIE rozumie súvislý blok dát, ktoré k sebe patria, napr. objednávka s jednotlivými položkami, alebo článok s komentármi. Typickí predstavitelia dokumentových databáz sú CouchDB, MongoDB a RavenDB, ktorá je popísaná v sekcii 5.3.

Stĺpcovo orientované databázy Vychádzajú z projektu Google BigTable. [18] Dáta sú uložené vo veľkej tabuľke po riadkoch s unikátnym identifikátorom, ale fyzicky sú uložené po stĺpcoch, čo urýchľuje vyhľadávanie podľa určitého atribútu, v stĺpcoch sú dáta prirodzene indexované. Sú vhodné pre ukladanie semi-štruktúrovaných dát, horizontálne škálovanie a paralelné spracovanie dopytov. Naopak, nie sú vhodné pre ukladanie dát, ktoré sú navzájom nejakým spôsobom prepojené. Najznámejšie databázy tohoto typu sú BigTable, HBase, HyperTable, Cassandra a Amazon SimpleDB.

Grafové databázy Dáta sú uložené v uzloch a vzťahoch medzi nimi, v hranách. Každý uzol obsahuje ukazateľ na susedný prvok. Takéto databázy sú veľmi rýchle v ukladaní prepojených, komplexných dát. Nie sú agregačne orientované a podporujú ACID transakcie. Predstavitelia: FlockDB, Neo4J, OrientD.

CAP teoréma NoSQL databázy sú vhodné k horizontálnemu škálovaniu, takéto riešenie je v praxi výhodné, ale prináša problém pri výpadku jednotlivých uzlov. CAP teoréma10 vyjadruje fakt, že každý takto škálovateľný systém môže spĺňať naraz dve z troch nasledujúcich vlastností: [19] • Konzistencia ( Consistency ): Každý uzol spracovávajúci danú požiadavku pracuje nad rovnakou množinou dát. • Dostupnosť ( Availability ): Za každých okolností užívateľ získa nejakú odpoveď na svoju požiadavku a vidí, či bola operácia úspešná, alebo neúspešná. • Tolerancia k rozdelení ( Tolerance to network partitions ): Systém bude funkčný aj pri výpadku niektorých uzlov, alebo časti siete. Jednotlivé typy systémov podľa CAP teorému sú: • CA systém (konzistencia a dostupnosť): Sem patria prevažne relačné databázové systémy, ktoré nefungujú pri výpadku jedného z uzlov, napr. SQL Server. • CP systém (konzistencia a tolerancia k rozdelení): Je obetovaná dostupnosť, napr. MongoDB.

10 Termín navrhol v roku 2000 Eric Brewer, formálny dôkaz poskytli Seth Gilbert a Nancy Lynch. 12 KAPITOLA 2: DATABÁZY A RELAČNÉ MODELOVANIE • AP systém (dostupnosť a tolerancia k rozdelení): Konzistencia nie je vyžadovaná pri veľkých distribuovaných systémoch, kde predstavuje obrovskú réžiu, napr. Cassandra, alebo CouchDB. V praxi u NoSQL databáz, ktoré bývajú typu CP a AP ide o voľbu medzi obetovaním dostupnosti na úkor konzistencie, alebo naopak. Fowlerov pohľad na CAP teorému sa dá vyjadriť ako obchodné rozhodnutie o type použitej NoSQL databázy, ktorá pracuje v distribuovanom systéme. Ide o databázu, ktorá pri výpadku jedného z uzlov neumožní ostatným spracovávať požiadavky, alebo ide o databázu, ktorá bude ďalej fungovať a eventuálne pripustí problémy v konzistencii dát, ktoré bude treba vyriešiť neskôr. [58] NoSQL databázy (okrem grafových) nepodporujú ACID 11 transakcie, najčastejšie z dôvodu obetovania konzistencie pri systémoch so stovkami uzlov. Preto sú takéto systémy nazývané ako BASE ( Basically available, Soft-state, Eventual consistency ). Sú teda prakticky stále dostupné, nie vždy konzistentné, ale časom sa do konzistentného stavu dostanú.

MapReduce MapReduce je algoritmus, resp. programovací model vyvinutý spoločnosťou Google umožňujúci spracovávanie výpočtovo náročných (databázových) operácií paralelne v clusteroch 12 . Od konkrétnej implementácie závisí, či je v clusteri jeden primárny uzol, ktorý spracuje požiadavku na MapReduce, alebo ide o uzol ľubovoľný. Tento iniciátor rozošle po ostatných uzloch požiadavku na funkciu Map, ktorá tým pádom nad celou množinou dát operuje paralelne. Tieto dáta nie sú menené a ako výsledok funkcií Map sú vrátené množiny záznamov, medzi ktorými sa môžu objaviť duplicitné hodnoty. Funkcia Reduce na iniciačnom uzle prijme tieto množiny záznamov funkcií Map a nad týmto vstupom po zoradení vykoná nejakú agregačnú operáciu, pri ktorej sú odstránené duplicitné hodnoty. V podstate funkcia Map operuje na dvojiciach kľúč1-hodnota1 z ktorých vytvára nové dvojice kľúč2-hodnota2. Funkcia Reduce spája hodnoty z nových dvojíc podľa spoločného kľúča. Hlavná výhoda celého konceptu je zjavná: funkcia Map môže bežať naraz v stovkách uzlov na sebe nezávislých. Indexy v databáze RavenDB sú implementované pomocou MapReduce, viď príloha B. Práca s NoSQL databázou a hlavné odlišnosti voči práci s relačným systémom (priamo, alebo prostredníctvom ORM nástroja) sú popísané v kapitole 8.

11 Akronym, ktorý vyjadruje základné charakteristiky transakcií v relačných databázach: Atomicity, Consistency, Isolation, Durability, preložené ako Atomicita, Konzistencia, Izolácia, Trvanlivosť. 12 Cluster je skupina navzájom komunikujúcich serverov, ktorá sa navonok tvári ako jeden celok. 13 Kapitola 3 Objektové modelovanie

Najviac viditeľný rozdiel medzi objektovým a relačným prístupom k modelovaniu je spôsob oddelenia logickej štruktúry dát od fyzického usporiadania. Relačné systémy logickú štruktúru dát od skutočného fyzického usporiadania oddeľujú, využívajú sa tabuľky a ich vzájomné prepojenia. Objektové systémy sa snažia z logickej štruktúry do fyzickej vrstvy pristupovať čo najpriamejšie a objekty majú medzi sebou definované vzťahy. 3.1 Vlastnosti objektu

Systémy vyjadrené pomocou objektového modelovania sa skladajú z objektov samotných, ktoré predstavujú ich základné stavebné kamene. Definícií pojmu „objekt“ je v literatúre mnoho:

Objekt je niečo, s čím môžete vykonávať rôzne veci. Objekt má stav, chovanie a identitu. Štruktúra a chovanie podobných objektov sú definované v ich spoločnej triede. Pojmy inštancia a objekt sú zameniteľné. [20]

Objekt označuje špecifický typ, resp. inštanciu triedy. Každý objekt má štruktúru podobnú ostatným objektom triedy, ale môže mu byť priradená individuálna charakteristika. Objekt môže volať funkcie špecifické danému objektu. [21]

Objekt je inštanciou nejakej triedy za behu programu. [22]

Objekt je individuálny a identifikovateľný prvok, buď abstraktný alebo reálny, ktorý obsahuje dáta o sebe samom a popisy manipulácie s týmito dátami. [23]

V zásade sa všetci autori zhodujú na niekoľkých spoločných znakoch objektu: ide o inštanciu triedy, obsahuje dáta a metódy, objekt má identitu a stav. To znamená, že dva objekty obsahujúce rovnaké dáta a metódy môžeme od seba odlíšiť. To je jeden z prvých rozdielov od relácií spomínaných v minulej kapitole, kde dve relácie obsahujúce rovnaké prvky môžeme chápať ako zameniteľné. Každý objekt je charakterizovaný práve jednou triedou .

3.1.1 Trieda Trieda popisuje štruktúru objektu a predstavuje zložitý dátový typ. Medzi jednoduché dátové typy patrí napríklad typ znak ( char ) alebo celé číslo ( integer ).

14 KAPITOLA 3: OBJEKTOVÉ MODELOVANIE Trieda sa skladá z dvoch základných prvkov, ktorými definuje spoločnú množinu rysov: z atribútov a z metód. Atribúty predstavujú vlastnosti, stavy objektu a metódami sa nazýva ich funkcionalita, resp. chovanie, ktorého je objekt schopný. Ukážku môže predstavovať trieda popisujúca napríklad televíziu. Medzi atribúty televízie patria vlastnosti ako výrobca, uhlopriečka, rozmery. Funkcionalitu televízie je možné charakterizovať metódami ako prepni program, zvýš hlasitosť, zmeň zdroj obrazu. Samozrejme je možné definovať desiatky ďalších atribútov a metód, konkrétna miera abstrakcie závisí od uváženia, čo je pre danú situáciu a daný model vhodné a podstatné. Medzi základné charakteristiky objektov, ktoré sú spoločné naprieč objektovo orientovanými jazykmi a ktoré súvisia s objektovo-relačným mapovaním sa dajú teda zaradiť nasledujúce: [24]

3.1.2 Identita Identita (Identity ) objektu ho odlišuje od všetkých ostatných objektov. Dva objekty obsahujúce rovnaké dáta, majúce rovnaký stav sú v skutočnosti od seba stále odlíšiteľné.

3.1.3 Stav Stav (State ) vyjadruje aktuálne hodnoty atribútov priradené konkrétnej identite objektu. Vďaka zapúzdrenosti objektov je stav viditeľný až po preskúmaní chovania daného objektu.

3.1.4 Chovanie Chovanie (Behavior ) je kolekcia operácií, ktoré objekt poskytuje (nazývaná rozhranie), kolekcia odpovedí, ktorými objekt odpovedá a kolekcia zmien, ktoré operácie v objekte vyvolajú.

3.1.5 Zapúzdrenie Zapúzdrenie ( Encapsulation ) poskytuje určitú formu abstrakcie a zabezpečuje aby nebolo možné z vonku vidieť implementačné detaily tejto abstrakcie. Ostatné objekty môžu využívať verejné metódy objektu, ale nevidia ako sú vo vnútri implementované. 3.2 Modelovanie s objektami

V objektovom prístupe k modelovaniu je systém charakterizovaný ako kolekcia objektov so vzájomnými vzťahmi. Objekty medzi sebou môžu komunikovať prostredníctvom zasielania správ, ktorými vyjadrujú požiadavky na zavolanie konkrétnych metód.

3.2.1 Dedičnosť Dedičnosť (Inheritance ) je jedným zo základných kameňov objektového modelovania. Dedičnosť umožňuje budovať hierarchickú štruktúru objektov, kde potomok získava

15 KAPITOLA 3: OBJEKTOVÉ MODELOVANIE atribúty a metódy svojho predka a rozširuje ho pridávaním vlastností nových, viď špecifické vlastnosti u objektov Kruh a Obdĺžnik na obrázku 3.1.

Obrázok 3.1: Dedičnosť

3.2.2 Polymorfizmus Polymorfizmus (Polymorphism ) je vlastnosť veľmi blízka dedičnosti, uvádza sa však oddelene. Keď je objektu poslaná správa, tak musí obsahovať metódu, ktorou na správu správne zareaguje. V hierarchii dedičnosti majú všetci potomkovia zdedené chovanie od svojho predka, ale keďže ide o samostatné triedy, tak je požadované aby na určitú správu reagovali odlišne, napr. každý tvar sa bude vykresľovať inak (obrázok 3.2).

Obrázok 3.2: Polymorfizmus 3.3 Vzťahy medzi objektami

Vzťahy medzi objektami sú implementované pomocou referencií, resp. pomocou ukazateľov. Vyjadrenie vzťahu jedného objektu s viacerými je možné pomocou poľa. Jednotlivé vzťahy sú zobrazené na obrázku 3.3.

3.3.1 Asociácia Asociácia ( Association ) predstavuje vzťah medzi dvoma objektami, ktoré spolu súvisia, ale nie sú na sebe navzájom závislé. Tento vzťah vyjadruje násobnosť medzi objektami. Napríklad existuje vzťah medzi objektami Študent a Učiteľ, ale tento vzťah sa nedá nazvať vzťahom má, lebo učiteľ študentov nevlastní.

16 KAPITOLA 3: OBJEKTOVÉ MODELOVANIE 3.3.2 Agregácia Agregácia ( Aggregation ) je špecializovaný asociačný vzťah, kde jeden objekt vlastní (má) iný objekt. V prípade zrušenia vlastníka nepríde k zrušeniu vlastneného a platí, že vlastnený objekt nie je na zrušenom objekte závislý. Agregácia býva niekedy zamieňaná s dedičnosťou. Hlavný rozdiel je práve v pomenovaní vzťahu medzi objektami: pri dedičnosti sa jedná o vzťah „je“, pri agregácii ide o vzťah „má“. Príkladu agregácie vyhovuje vzťah medzi objektami Katedra a Učiteľ. Učitelia patria pod katedru, ale v prípade jej zrušenia nepríde k zrušeniu učiteľov, budú existovať aj naďalej.

3.3.3 Kompozícia Kompozícia (Composition ) predstavuje posledný asociačný vzťah, keď jeden objekt pozostáva z iných. Ide o ďalšiu špecializáciu agregácie. Objekt Fakulta má objekty Katedra, ale v prípade zrušenia fakulty zanikajú aj jej katedry, čiže existencia vlastneného objektu je na vlastníkovi v kompozícii existenčne závislá.

Obrázok 3.3: Typy vzťahov medzi objektami [25], [26]

3.3.4 Násobnosť vo vzťahoch Podobne ako násobnosti medzi reláciami v relačnom modeli (podsekcia 2.2.3), existujú násobnosti vo vzťahoch medzi objektami, viď obrázok 3.4. • Vzťah 1:1: Maximálna násobnosť na každej zo strán vzťahu je jedna. Jeden index patrí práve jednému študentovi a jeden študent vlastní práve jeden index. • Vzťah 1:N: Do tejto kategórie rovnako spadá aj vzťah N:1. Násobnosť na jednej strane vzťahu je maximálne jedna, na opačnej strane vzťahu viac ako jedna. Fakulta v skutočnosti obsahuje viacero katedier, ale jedna katedra spadá práve pod jednu fakultu.

17 KAPITOLA 3: OBJEKTOVÉ MODELOVANIE • Vzťah M:N: Násobnosť na každej zo strán vzťahu môže byť viac ako jedna. Napríklad učiteľ môže vyučovať viacero študentov a každý študent môže študovať u viacerých učiteľov.

Obrázok 3.4: Násobnosti vo vzťahoch

3.3.5 Smer vzťahu Typ vzťahu z hľadiska smeru medzi dvoma objektami môže byť jednosmerný alebo obojsmerný. Pri jednosmernom vzťahu len jeden z objektov pozná ten druhý s ktorým tvorí vzťah. Obojsmerný vzťah nastane ak o sebe vedia objekty na oboch stranách. Toto je nutné v objektových jazykoch riešiť programovo, štandardné správanie je jednosmerné. Takéto chovanie je presne opačné oproti relačnému modelovaniu, kde je vzťah medzi oboma reláciami prirodzene obojsmerný.

18 Kapitola 4 Objektovo-relačné mapovanie

Dáta aplikácií sú najčastejšie ukladané do relačných databáz, pri vývoji aplikácií samotných je využívaný objektový prístup. Obe tieto technológie sú dlhodobo zaužívané a domnievať sa, že situácia bude o pár rokov iná by bolo veľmi optimistické. Objektovo- relačné mapovanie (ďalej len ORM) je technológia, ktorá nám umožní prevádzať dáta medzi relačnou databázou a objektami v objektovo orientovaných jazykoch. ORM teda zaisťuje prepojenie aplikácie s databázou pomocou mapovania tried na databázové tabuľky. Dnes ide o bežnú súčasť softvérového vývoja. Oba rozdielne prístupy k modelovaniu sú popísané v predchádzajúcich kapitolách 2 a 3, ich prepojenie však prináša špecifické problémy, ktoré je nutné riešiť, napr. dedičnosť ako jeden z typických rysov objektového programovania v relačných databázach zastúpená nie je. Súhrnný názov týchto problémov býva v angličtine označovaný ako Object-relational impedance mismatch , veľmi voľne preložiteľný ako Objektovo-relačná nezhoda. Skrátene sa tieto nezhody nazývajú aj ako Impedance mismatch. 4.1 Impedance mismatch

Je to sada problémov a rozdielov medzi relačným a objektovým prístupom k modelovaniu. Táto problematika sa objavuje, keď je relačný databázový systém používaný v aplikácii napísanej v objektovo orientovanom jazyku. Phill Haack vo svojom blogu termín Impedance mismatch vysvetľuje takto:

„Nezhoda sa týka rozdielov v štruktúre medzi normalizovanou relačnou databázou a typickou objektovo orientovanou hierarchiou tried. Snaha o prirodzené mapovanie databázy na objektový model sa dá prirovnať snahe o spojenie dvoch magnetov cez ich severné póly. Termín impedancia sa často používa v elektrotechnike, kde označuje zdanlivý odpor súčiastky voči striedavému prúdu. Predstavte si ručné svietidlo na bežné batérie typu AAA. Po pripojení výkonnej autobatérie bude svietidlo schopné využiť len zlomok možnej energie. Naopak, pripojenie batérií typu AAA k výkonnému reflektoru opäť vyústi k neefektívnemu využitiu energie. Ručné svietidlo bude efektívne fungovať práve so správnymi batériami, kde maximálne využije ich potenciál. V softvérovom inžinierstve si môžeme predstaviť tok dát analogicky k elektrickému prúdu. Vtedy impedancia relačného modelu nie je v súlade s impedanciou hierarchie objektov, takže k dátam nemôžeme pristupovať s maximálnou efektivitou, čo je výsledok problémov typu Impedance mismatch“. [27]

19 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE Mark Fussel vo svojej publikácii zdôrazňuje hlavné odlišnosti medzi oboma prístupmi a definuje Impedance mismatch takto:

Objektové modelovanie popisuje systémy objektami, ktoré majú identitu, chovanie a zapúzdrený stav. Relačné modely popisujú systém informáciami. Situácia vyzerá na prvý pohľad tak, že relačné modelovanie nemôže žiadnym spôsobom reprezentovať vlastnosti objektového modelovania. N-tice nepodporujú ani identitu, ani zapúzdrenie a ich hodnoty nemajú stav. [24]

Mnohé charakteristické prvky objektového modelovania nemajú v relačnom svete svoj ekvivalent. Napr. zapúzdrenie, dedičnosť a polymorfizmus (kapitola 3) nie sú podporované. Existujú relačné databázové systémy, ktoré síce niektoré objektové prvky podporujú (podsekcia 2.3.2), ich primárnou úlohou však je v prvom rade efektívne ukladanie dát v relačnej forme. Rozdiely sú aj v používaných dátových typoch. V relačných systémoch je typicky používaný dátový typ pre ukladanie textových reťazcov varchar , analogicky použiteľný typ v objektových jazykoch je string . Unikátnosť relácií je vyjadrená primárnym kľúčom, v objektovom modelovaní podobná funkcionalita neexistuje. Cudzie kľúče sprostredkovávajú vzťahy medzi reláciami navzájom, v objektovom svete ich nahrádzajú referencie (ukazatele) na objekty. Odlišnosti sa nevyskytujú len v rozdielnom pohľade na modelovanie, ale aj v prístupe ako takom. Relačné modelovanie je založené na matematickom aparáte relačnej algebry (podsekcia 2.2.3) a je popisované deklaratívnymi jazykmi, ktoré vyjadrujú čo sa má spočítať. Relačné systémy sa zameriavajú na znalosti ( concerned with knowledge ). Jazyky objektívneho sveta sú imperatívne a v sekvencii krokov určujú ako sa má daná vec spočítať. Sú zamerané na chovanie ( concerned with behavior ). Celé ORM je tým pádom zložitejšie ako by mohlo byť. [24]. Nasledujúca tabuľka 4.1 sumarizuje zásadné rozdiely medzi objektovým a relačným prístupom. Na jednom riadku sa vždy nachádzajú pojmy, ktoré spolu súvisia. Objektový prístup Relačný prístup trieda relácia (tabuľka) objekt n-tica (riadok) jednosmerná asociácia obojsmerná asociácia stav dáta ukazateľ z vlastníka cudzí kľúč na vlastnenom dedičnosť bez dedičnosti polymorfizmus bez polymorfizmu vzťah M:N spájanie relácií (tabuliek) Tabuľka 4.1: Rozdiely medzi objektovým a relačným svetom

20 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE Ďalším problémom, ktorý sa v praxi vyskytuje je nedodržiavanie všetkých normálnych foriem databáz, napriek častým odporúčaniam. Nie všetky databázy sú v praxi navrhnuté správne. Mnoho databáz bolo na začiatku navrhnutých nie zrovna ideálnym spôsobom a vďaka ostrému nasadeniu v produkcii a množstvu systémov na nich závislých, je veľký problém zmeniť ich štruktúru tak, aby vyhovovali všetkým pravidlám. 4.2 Mapovanie objektov na relácie

Pre korektné fungovanie ORM musia existovať postupy, ako určité prvky objektového modelovania transformovať do relačného sveta.

4.2.1 Mapovanie dedičnosti Relačné databázy nepoznajú mechanizmus, ktorým by bolo možné prirodzene zachytiť dedičnosť tried. Existuje viacero spôsobov ako je možné dáta tried zaznamenať v tabuľkách databázy. Nasledujú štyri základné, v literatúre najčastejšie uvádzané spôsoby mapovania dedičnosti. Ich bližší popis vrátane návrhových vzorov sa nachádza v podsekcii 4.3.4. • Uloženie celej štruktúry dedičnosti do jednej tabuľky: Všetci potomkovia jednej triedy (celá hierarchia) sa nachádzajú v jednej databázovej tabuľke. Tento spôsob mapovania je inšpirovaný návrhovým vzorom Dedičnosť jednej tabuľky. • Uloženie každej konkrétnej triedy do vlastnej tabuľky: V tomto prípade nie sú do tabuliek mapované abstraktné triedy, ale len konkrétne. Každá tabuľka obsahuje všetky atribúty triedy vrátane zdedených. Túto stratégiu popisuje vzor Dedičnosť konkrétnej tabuľky. • Uloženie každej triedy do vlastnej tabuľky: Každá z tried je uložená vo vlastnej tabuľke spolu so všetkými jej atribútmi a unikátnym identifikátorom. Tento spôsob je podobný predchádzajúcemu, ukladá však do tabuliek aj abstraktné triedy. Návrhový vzor, ktorý charakterizuje tento spôsob mapovania dedičnosti sa volá Dedičnosť tabuľky triedy. • Uloženie tried do generickej štruktúry tabuliek: Poslednou možnosťou mapovania tried dedičnosti do tabuliek je prístup formou metadát. Ambler spomína aj techniku mapovania viacnásobnej dedičnosti, ktorú podporujú staršie jazyky ako C++ , ale modernejšie ako Java a C# viacnásobnú dedičnosť nepodporujú, jej reálne použitie v projektoch je diskutabilné a dá sa nahradiť použitím rozhraní. [28]

4.2.2 Mapovanie smeru vo vzťahoch V podsekcii 3.3.5 sú spomínané dva spôsoby, ktoré môže nadobúdať smer vzťahu medzi objektami. Relačné modelovanie nepozná koncept jednosmerného vzťahu, vďaka cudzím kľúčom sú všetky vzťahy obojsmerné.

21 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE Mapovanie jednosmerných a obojsmerných objektových vzťahov je teda v relačnom modelovaní triviálne.

4.2.3 Mapovanie násobností vo vzťahoch Sekcie 2.2.3 a 3.3 popisujú rôzne druhy násobnosti vzťahov medzi reláciami a medzi objektami. Pre mapovanie každého druhu násobnosti existuje niekoľko techník, je dôležité v mapovaní hodnotu násobnosti zachovať.

Obrázok 4.1: Násobnosti objektového modelu Na obrázkoch 4.1 a 4.2 sú v objektovom a relačnom modeli znázornené tri násobné vzťahy: 1:1 medzi Zamestnancom a Pozíciou, 1:N medzi Divíziou a Zamestnancom a M:N medzi Zamestnancom a Úlohou. [28]

Obrázok 4.2: Násobnosti relačného modelu 22 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE Tabuľka 4.2 vyjadruje mapovanie vlastností medzi oboma modelmi:

Objekt.vlastnosť Tabuľka.Stĺpec Pozícia.názov Pozícia.Názov Pozícia.pozíciaID Pozícia.PozíciaID Zamestnanec.meno Zamestnanec.Meno Zamestnanec.zamestnanecID Zamestnanec.ZamestnanecID Zamestnanec.zamestnanecID ZamestnanecÚloha.ZamestnanecID Divízia.názov Divízia.Názov Divízia.divíziaID Divízia.DivíziaID Úloha.popis Úloha.Popis Úloha.úlohaID Úloha.ÚlohaID Úloha.úlohaID ZamestnanecÚloha.ÚlohaID Tabuľka 4.2: Mapovanie vlastností Z objektov sú mapované len biznis vlastnosti a tieňové informácie ( Shadow information ). Medzi tieňové informácie u objektov patria také vlastnosti, ktoré nie sú potreba pre charakteristiku objektu samotného, ale využívajú sa pre správu a ukladanie do databáze, typicky ide o hodnoty primárnych kľúčov. V UML diagrame na obrázku 4.1 sú označené stereotypom „ persistence “. V tabuľke 4.2 sa nenachádzajú konštrukčné vlastnosti (scaffold properties ), tj. vlastnosti, ktoré sa používajú pre modelovanie obojsmerných vzťahov.

Mapovanie vzťahu 1:1 Pri mapovaní vzťahu medzi Zamestnancom a Pozíciou je žiadané chovanie, keď je treba pri načítaní objektu Zamestnanec automaticky načítať aj objekt Pozícia a naopak. Tabuľka 4.3 zobrazuje detaily 13 mapovania tohoto chovania. Napr. pri načítaní Pozície sa tento objekt uloží do pamäte. Automaticky sa skontroluje príslušný vzťah („je držaná“) a pomocou hodnoty Pozícia.ZamestnanecID je identifikovaný unikátny objekt Zamestnanca, ktorý je potreba do pamäte načítať tiež. Prehľadá sa tabuľka so zamestnancami, nájde sa záznam s príslušným ID, načíta sa, vytvorí sa príslušný objekt a jeho referencia sa nastaví do objektu Pozícia. Postup je obdobný pri načítaní objektu Zamestnanec. Objekt Zamestnanec sa uloží do pamäte, skontroluje sa vzťah „drží“. Podľa hodnoty Zamestnanec.ZamestnanecID sa nájde v tabuľke Pozícia príslušná pozícia a vytvorí sa objekt. Do vlastnosti Zamestnanec.pozícia sa uloží referencia na novovzniknutý objekt Pozícia. Takúto závislosť dvoch objektov treba vyriešiť pri ukladaní. Aby sa zachovala referenčná integrita, sú používané databázové

13 Názov stĺpca N znamená násobnosť, AN znamená automatické načítavanie. 23 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE transakcie. Aktualizácia každého z objektov je vykonaná vlastným update príkazom jazyka SQL v rámci spoločnej transakcie. V praxi nie je dôležité, či sa cudzí kľúč vyjadrujúci vzťah 1:1 nachádza v prvej, alebo v druhej tabuľke, takže tabuľka Zamestnanec môže obsahovať FK do tabuľky Pozícia, alebo naopak, viď obrázok 4.2. Podstatné je obmedzenie, aby FK ukazoval na existujúci riadok odkazovanej tabuľky. [28] Vzťah Z Konštrukčná medzi Do objektu N AN Stĺpec objektu vlastnosť objektami drží Zamestnanec Pozícia 1 Á Pozícia.ZamestnanecID Zamestnanec.pozícia je držaná Pozícia Zamestnanec 1 Á Pozícia.ZamestnanecID Zamestnanec.pozícia pracuje v Zamestnanec Divízia 1 Á Zamestnanec.DivíziaID Zamestnanec.divízia má Divízia Zamestnanec M N Zamestnanec.DivíziaID Divízia.zamestnanci pracujúcich má Zamestnanec.ZamestnanecID Zamestnanec Úloha M N Zamestnanec.úlohy pridelenú ZamestnanecÚloha.ZamestnanecID Úloha.ÚlohaID je pridelená Úloha Zamestnanec M N Úloha.zamestnanci ZamestnanecÚloha.ÚlohaID Tabuľka 4.3: Detaily mapovania

Mapovanie vzťahu 1:N Automatické načítavanie pri vzťahu 1:N by malo fungovať iba jedným smerom. Pri načítaní objektu Zamestnanec je vhodné automaticky načítať aj objekt Divízia analogickým spôsobom ako v prípade mapovania 1:1 (tabuľka 4.3). Opačným smerom toto chovanie neplatí. Problém môže nastať ak je do pamäte načítaných niekoľko zamestnancov jednej divízie. Každý objekt Zamestnanec tak drží referenciu na vlastnú kópiu objektu Divízia (všetky objekty majú rovnaké DivíziaID), pritom žiaduce chovanie je, aby každý objekt Zamestnanec odkazoval na spoločný objekt Divízia. Riešením je používanie medzipamäte, ktorá zaistí aby sa v pamäti nemohlo nachádzať niekoľko objektov s rovnakým ID, takže v každom čase bude v pamäti maximálne jeden objekt Divízia pre dané ID. Ďalším riešením je vytvorenie kolekcie objektov Divízia. Aplikácia potom nastaví referenciu na patričný objekt Divízia a zavolá operáciu Divízia.pridajZamestnanca(). Ukladanie objektov do databáze prebieha rovnako ako v prípade mapovania 1:1. [28]

Mapovanie vzťahu M:N Pre implementáciu vzťahu tohoto typu je nutné použiť asociačnú tabuľku, ktorej jediný účel je udržovanie vzťahu medzi dvomi a viacerými tabuľkami v relačnej databáze. Vzťah typu M:N je medzi objektami Zamestnanec a Úloha. Asociačná tabuľka sa volá ZamestnanecÚloha a obsahuje cudzie kľúče ZamestnanecID a ÚlohaID. Namiesto násobnosti M:N v objektovom modeli, tak vzniknú dve násobnosti 1:N a načítavanie príslušných dát využíva spájanie tabuliek. [28]

24 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE 4.3 Princípy fungovania ORM

Martin Fowler vo svojej knihe (Patterns of enterprise application architecture [29]) popísal návrhové vzory poskytujúce najlepšie praktiky mapovania objektov na relácie databáze.

4.3.1 Návrhové vzory Prvýkrát sa návrhové vzory objavili v roku 1995 v publikácii Design Patterns: Elements of Reusable Object-Oriented Software autorov Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. [30] Vzory napomáhajú znovu-použiteľnosti objektovo orientovaného kódu, popisujú problémy, ktoré sa pri vývoji opakujú a navrhujú najlepšie postupy ako dané problémy vyriešiť. Sami autori návrhové vzory definujú takto:

Sú to jednoduché a elegantné riešenia špecifických problémov v návrhu objektovo orientovaného softvéru. [30]

Spolu bolo predstavených päť tvoriacich vzorov (Creational patterns ), sedem štrukturálnych vzorov (Structural patterns ) a jedenásť vzorov chovania ( Behavioral patterns ). Ich popis je nad rámec tejto práce, čitateľ je odkázaný na knihy [30], alebo [31]. Návrhové vzory týkajúce sa priamo objektovo-relačného mapovania predstavil roku 2002 Martin Fowler v spomínanej knihe na začiatku sekcie. Táto publikácia v prvej časti ponúka návod na tvorbu enterprise aplikácií, v časti druhej detailne popisuje všetky využité návrhové vzory k tomu potrebné. V nasledujúcej časti práce budú spomenuté vzory tak, ako ich publikoval Fowler vrátane obrázkov, ktoré sú v malej miere prispôsobené a lokalizované.

4.3.2 Vzory architektúry Prvá skupina vzorov architektúry (Architectural patterns ) zahŕňa vzory pomocou ktorých aplikácia komunikuje s databázou. Vzorová tabuľka Osoba, na ktorej budú tieto vzory demonštrované, je na obrázku 4.3.

Obrázok 4.3: Tabuľka Osoba

25 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE Brána k dátam tabuľky Úlohou tohto objektu (Table Data Gateway ) je byť bránou 14 k tabuľke databázy a umožniť prístup ku všetkým jej riadkom. Objekt udržuje všetky potrebné SQL príkazy a sprístupňuje ich funkcionalitu pomocou metód. Medzi SQL príkazy patrí vkladanie (insert ), aktualizácia ( update ), mazanie ( delete ) a dopytovanie ( select ) dát podľa rôznych parametrov. Táto funkcionalita sa nazýva aj ako CRUD 15 operácie a celé chovanie vzoru je zapúzdrením databázových operácií. Na obrázku 4.4 je štruktúra triedy BránaKOsobe (PersonGateway ), ktorá zabezpečuje patričné operácie.

Obrázok 4.4: Brána k dátam tabuľky

Brána k dátam riadku Tento vzor (Row Data Gateway ) je podobný predchádzajúcemu s tým rozdielom, že tvorí bránu k jednému riadku databázy. Objekt existuje pre každý jeden riadok. Objekt BránaKOsobe funguje ako predchádzajúci vzor a zabezpečuje všetky databázové operácie okrem vyhľadávania, na ktoré je využitý špeciálny vyhľadávací objekt VyhľadávačOsoby ( PersonFinder ). Tento objekt po vyhľadaní samotného riadku vytvára jeho inštanciu. BránaKOsobe neobsahuje žiadnu doménovú logiku a to je hlavný rozdiel od nasledujúceho vzoru.

Obrázok 4.5: Brána k dátam riadku

14 Bránou je nazvaný objekt, ktorý obaľuje prístup k externým zdrojom 15 Create, Update, Read, Delete 26 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE Aktívny záznam Aktívny záznam (Active Record ) sa chová podobne ako predchádzajúci vzor, pridáva však k dátam doménovú logiku. Objekt opäť umožňuje prístup k jednému riadku databázy. Zvolenie vzoru Aktívny záznam je výhodné použiť v prípade jeho podobnosti k tabuľke v databáze, teda v prípadoch, keď nie je potrebné zachytávať dedičnosť objektov.

Obrázok 4.6: Aktívny záznam Typické metódy vykonávajú nasledovné činnosti: • Vytvorenie inštancie Aktívneho záznamu z množiny výsledkov SQL dopytu. • Vytvorenie novej inštancie pre oneskorené vloženie do databázy. • Statické metódy obaľujúce najčastejšie používané SQL dopyty. • Aktualizácia databázy vložením dát Aktívneho záznamu. • Získavanie a nastavovanie hodnôt atribútov. • Implementácia častí biznis logiky aplikácie. Nevýhodu tohto vzoru predstavuje práve nutnosť izomorfnosti (podobnosti) so zložitým databázovým modelom, ktorá komplikovaná na dodržanie pri zložitých a komplexných aplikáciách. Riešenie poskytuje nasledujúci vzor Mapovač dát.

Mapovač dát Vrstva mapovača (Data Mapper ), nachádzajúca sa medzi samotným objektom a databázou umožňuje, aby boli na sebe nezávislé.

Obrázok 4.7: Mapovač dát Doménový objekt teda neobsahuje žiadne CRUD operácie, ale obstaráva ich oddelený mapovací objekt, ktorého hlavnou úlohou je transformácia objektových dát na databázové a naopak. Mapovač má prístup aj k doménovému modelu, ale aj priamo do databázy. V praxi môže byť tento vzor implementovaný pomocou viacerých objektov.

27 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE Vďaka oddeleniu doménovej logiky a databázových operácií je možné nahradiť databázu inou bez zložitých zmien v aplikácii samotnej. Primárnym použitím tohto vzoru sú systémy, kde je potreba nezávislosti vývoju databázy od doménového modelu.

4.3.3 Vzory objektovo-relačného chovania Tieto vzory ( Object-Relational Behavioral Patterns ) sa starajú o konzistenciu dát medzi aplikáciou a databázovým úložiskom. Majú na starosti zabezpečiť správne načítavanie a ukladanie objektov do databázy, zamedziť uviaznutiam, konkurenčnému čítaniu dát a obmedziť duplicitné načítavanie už načítaných dát.

Mapa identity Mapa identity ( Identity map ) zabezpečuje, aby bol každý objekt z databáze do pamäte načítaný len raz.

Obrázok 4.8: Mapa identity Diagram aktivít na obrázku 4.9 znázorňuje chovanie vzoru: Vyhľadávač hľadá objekt s id = 1. Pozrie sa do mapy identity a overí, či bol tento objekt z databázy už načítaný. Ak ho v mape identít nájde, tak vráti jeho referenciu aplikácii, v opačnom prípade je objekt načítaný z databáze a táto informácia je uložená do mapy. Pre každú tabuľku z databáze spravidla existuje jedna mapa identít. Vzor zároveň zaručuje konzistenciu načítaných dát, záznam nie je načítaný do rôznych objektov viackrát.

Pracovná jednotka Úlohou Pracovnej jednotky (Unit of Work ) je správa a koordinácia ukladania dát do databázy. Sleduje zmeny na objekte a umožňuje zápis dávkovo, takže optimalizuje výkon aplikácie a minimalizuje množstvo dopytov. Zároveň sleduje načítané objekty z databáze a eliminuje zbytočné duplicitné načítavanie. Je základným vzorom pre správu transakcií a transakčných konfliktov. Na obrázku 4.8 je schéma 16 vzoru. Pri zmenách atribútov objektu sa tieto zmeny premietajú do špinavého stavu ( dirty state ) objektu a až po požiadavku na trvalé uloženie

16 Pojmy commit a rollback sa používajú pri potvrdení, resp. zrušení databázovej transakcie. 28 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE dát sú všetky zmeny naraz uložené v databáze. Rovnako sa vzor chová pri tvorbe nového objektu, keď je vytvorený jeho čistý stav ( clean state ), následne špinavý stav a až potom sa objekt ukladá trvalo.

Obrázok 4.9: Pracovná jednotka

Lenivé nahrávanie Vzor lenivé nahrávanie (Lazy load ) zabezpečuje nahrávanie objektov z databáze až v momente, keď sú potrebné. Na obrázku 4.10 je diagram aktivít tohoto vzoru.

Obrázok 4.10: Lenivé nahrávanie Po vytvorení objektu Zákazník je potrebné z databázy načítať jeho objednávky. V prípade ich veľkého množstva je táto operácia časovo a pamäťovo náročná. Riešením je lenivé nahrávanie, ktorého úlohou je pristupovať k dátam v databáze až v momente keď sú skutočne potrebné. Existujú štyri spôsoby ako je možné vzor Lenivé nahrávanie implementovať: 1. Lenivá inicializácia ( Lazy initialization ): Ide o najjednoduchší prístup. Pri načítavaní hodnôt pomocou prístupových metód sa hodnoty kontrolujú s typom null. Ak sú hodnoty null, tak sa načítajú z databáze, v opačnom prípade sa použije už načítaná hodnota.

29 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE 2. Virtuálny prostredník (Virtual proxy 17 ): Objekt je nahradený virtuálnym prostredníkom, ktorý implementuje rovnaké rozhranie ako originálny objekt. Zavolanie virtuálnej metódy deleguje volanie na metódu skutočného objektu a načítanie dát je uskutočnené v tomto momente. K jednému virtuálnemu objektu môže byť pristupované pomocou viacerých prostredníkov. 3. Vlastník hodnoty ( Value holder ): Ide o objekt, ktorý obaľuje iný objekt. Pre získanie hodnoty vnútorného objektu je nutné požiadať o hodnotu ten vonkajší, dáta sú z databázy načítané len pri prvom prístupe. Pri ďalších prístupoch je vrátený už inicializovaný objekt. 4. Duch ( Ghost ): Objekt po vytvorení obsahuje len jeho ID, nie sú načítané žiadne ďalšie atribúty. Až v momente prístupu k týmto atribútom sú vykonané patričné databázové operácie a dáta sú načítané.

4.3.4 Vzory objektovo-relačnej štruktúry Tieto vzory (Object-Relational Structural Patterns ) sa zaoberajú mapovaním objektov a ich štruktúrou. Nasledujúce štyri návrhové vzory charakterizujú rôzne spôsoby mapovania dedičnosti. Priložené UML diagramy sa podobajú na pôvodné diagramy uverejnené Fowlerom [29], ale z dôvodu zrozumiteľnosti popisujú hierarchiu ukážkovej dedičnosti objektu Osoba (obrázok 4.17), kde dve triedy Zákazník a Zamestnanec dedia od abstraktnej triedy Osoba, trieda Manažér ďalej dedí od triedy Zamestnanec.

Obrázok 4.11: Ukážková hierarchia dedičnosti

17 Vzor Proxy predstavuje triedu poskytujúcu rozhranie k ďalšej funkcionalite. 30 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE Dedičnosť jednej tabuľky Vzor Dedičnosť jednej tabuľky ( Single table inheritance ) ukladá celú hierarchiu do jednej tabuľky. Ukážková tabuľka zachytávajúca vzorový príklad dedičnosti sa nachádza na obrázku 4.18.

Obrázok 4.12: Dedičnosť jednej tabuľky Vo výslednej tabuľke je uložený každý z atribútov, navyše sú pridané dva stĺpce. OsobaPOID 18 figuruje v pozícii primárneho kľúča a zabezpečuje jedinečné ID každého namapovaného objektu v tabuľke. OsobaTyp identifikuje typ objektu, aby bolo možné následne z databáze tento objekt obnoviť. Toto rozdelenie nemusí byť vždy zrozumiteľné, v praxi sa často používajú atribúty typu boolean, pre každú z tried jeden. V tomto prípade by atribút OsobaTyp bol nahradený atribútmi JeZákazník, JeZamestanec a JeManažér. Pre pridanie novej triedy stačí do tabuľky pridať patričné stĺpce charakterizujúce nové atribúty. Jedna tabuľka pre celú hierarchiu dedičnosti je prehľadnejšia v prípade, že hierarchia nie je moc veľká. Naopak, pri zvýšení počtu tried a atribútov v nich takáto tabuľka enormne narastá a orientácia v nej je veľmi zložitá. Získavanie dát je z dôvodu ich sústredenia na jedno miesto veľmi rýchle. Medzi hlavné nevýhody patrí aj veľké množstvo null hodnôt s ktorými nie všetky databázy dokážu efektívne pracovať. V každom riadku sa nachádza veľa nerelevantných stĺpcov, ktoré patria iným triedam. Tento spôsob modelovania je obzvlášť výhodný pre malé hierarchie dedičnosti ideálne bez prekrývania sa typov v hierarchii.

18 POID z angl. Persisent Object Identifier, umelo vytvorená hodnota, neprejavuje sa v aplikácii. 31 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE Dedičnosť tabuľky triedy Podstatou tohto vzoru ( Class Table Inheritance ) je uloženie každej triedy do vlastnej tabuľky. Napríklad dáta Zákazníka sú uložené v dvoch tabuľkách: v tabuľke Zákazník a Osoba, takže pre získanie hodnoty uloženého objektu Zákazník je nutné spojiť obe dve tabuľky príkazom join.

Obrázok 4.13: Dedičnosť tabuľky triedy

Dedičnosť konkrétnej tabuľky Vo vzore Dedičnosť konkrétnej tabuľky ( Concrete Table Inheritance ) sú do vlastných tabuliek ukladané len konkrétne triedy, viď obrázok 4.19.

Obrázok 4.14: Dedičnosť konkrétnej tabuľky

32 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE Každá z tabuliek obsahuje vlastný identifikátor typu POID. Tento typ ukladania tried do tabuliek je hospodárnejší, lebo každá tabuľka obsahuje len relevantné stĺpce s hodnotami atribútov, hodnôt typu null je menej ako v predchádzajúcom prípade. Primárne kľúče jednotlivých tabuliek musia byť unikátne v rámci celej hierarchie z dôvodu jednoznačnej identifikácie uloženého objektu. V prípade modifikácie triedy je nutné zmeniť patričnú tabuľku a ak sa jedná o nadradenú triedu, tak treba zmeniť aj všetky tabuľky patriace jej potomkom. Primárny kľúč OsobaPOID je využitý ako cudzí kľúč v triedach potomkov a slúži k navigácii medzi tabuľkami. Tento spôsob modelovania veľmi dobre podporuje polymorfizmus a zmeny v hierarchii dedičnosti, lebo stačí pridať alebo zmeniť len jednu tabuľku. Rovnako je najvhodnejší pre prostredie s častými zmenami v atribútoch. Prístup k dátam je však pomalší vďaka nutnosti pristupovať k mnohým tabuľkám naraz.

Mapovače dedičnosti Mapovače dedičnosti ( Inheritance Mappers ) predstavujú štruktúru na organizáciu databázových mapovačov, ktoré sú využívané pri mapovaní dedičnosti.

Obrázok 4.15: Mapovače dedičnosti Táto štruktúra je kompatibilná s predchádzajúcimi tromi vzormi a je určená k optimalizácii načítavania a ukladania dát do databázy, vrátane operácií s abstraktnými triedami. Jednotlivé dielčie mapovače môžu byť organizované podobne ako je organizovaný hierarchický model dedičnosti, ktorý popisujú, viď obrázok 4.21. Každá konkrétna trieda modelu má vlastný mapovač s metódami na hľadanie, vkladanie, aktualizáciu a mazanie. Metóda nájdi vyhľadá príslušný riadok v databázovej tabuľke, vytvorí objekt správneho 33 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE typu a vloží do neho dáta. Metódu vlož implementuje každý mapovač, po vložení dát napr. objektom Mapovač manažéra sa riadenie predá nadradenej triede a tá vloží do vzniknutého objektu vlastné dáta, nakoniec dáta vloží najvyššie položená abstraktná trieda. Operácie na vkladanie a aktualizáciu dát fungujú obdobne. V štruktúre sú ďalšie dva mapovače, najvyššie postavený Mapovač, ktorý má na starosti samotné zapisovanie a čítanie dát a konkrétny Mapovač osoby, ktorého operácie sa odohrávajú na úrovni triedy Osoba.

Generická štruktúra tabuliek Tento návrhový vzor nepochádza od Fowlera [29], ale od Amblera [28]. Na obrázku 4.22 je znázornená štruktúra tabuliek, ktorá podporuje nielen dedičnosť, ale vďaka svojej flexibilite aj vzťahy medzi triedami.

Obrázok 4.16: Generická štruktúra tabuliek V tabuľke Trieda sú uložené názvy jednotlivých tried spolu s ich ID, ktoré sú cudzím kľúčom v tabuľke Dedičnosť definujúcej hierarchiu medzi triedami. Každý atribút z tried je charakterizovaný jedným riadkom v tabuľke Atribút s referenciou na tabuľky Hodnota a TypAtribútu, kde sú uložené príslušné hodnoty a typy atribútov. Samotná hodnota je typu varchar a podľa potreby je konvertovaná na skutočný typ atribútu. Tento spôsob nie je vhodný pre rozsiahle hierarchie tried, lebo je nutné načítať veľmi veľa riadkov pre obnovenie uloženého objektu.

Pole identity Vzor Pole identity ( Identity field ) ukladá ID objektu z databázy (primárny kľúč) a zabezpečuje tak identitu medzi databázovým riadkom a objektom v pamäti.

34 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE

Obrázok 4.17: Pole identity Riadky v databáze sú navzájom odlíšené ich primárnym kľúčom, objekty v pamäti takéto odlíšenie nepotrebujú, systém vnútorne ich identitu odlišuje. Pole identity len ukladá primárne kľúče riadkov ako atribúty objektov.

Mapovanie cudzích kľúčov Mapovanie cudzích kľúčov (Foreign key mapping ) mapuje asociáciu medzi dvoma objektami na referenciu cudzieho kľúča medzi databázovými tabuľkami.

Obrázok 4.18: Mapovanie cudzích kľúčov Objekty medzi sebou vytvárajú asociácie pomocou referencií. Na obrázku 4.12 je asociácia medzi Albumom a Umelcom, kde Album „má“ práve jedného Umelca, teda v objekte Album je referencia na objekt Umelec. V relačnom modelovaní sa táto asociácia vyjadrí cudzím kľúčom v tabuľke Albumy.

Mapovanie asociačnej tabuľky Tento vzor ( Association table mapping ) ukladá asociáciu medzi dvoma objektami ako tabuľku s cudzími kľúčmi, ktoré odkazujú na tabuľky popisujúce pôvodné objekty v asociácii.

35 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE

Obrázok 4.19: Mapovanie asociačnej tabuľky Zamestnanec z obrázku 4.13 môže disponovať viacerými schopnosťami, každú schopnosť môže mať niekoľko zamestnancov. Objekt zamestnanec udržuje kolekciu referencií na schopnosti, tak ako si objekt schopnosť udržuje kolekciu referencií na príslušných zamestnancov. V databáze nie je možné využiť cudzie kľúče na mapovanie vzťahu s násobnosťou M:N, tak je pre tento účel využitá pomocná tabuľka Schopnosti- Zamestnanci udržujúca len cudzie kľúče a žiadny primárny kľúč.

Mapovanie závislosti Mapovanie závislosti ( Dependent mapping ) predstavuje koncept mapovania triedy, ktorá je závislá na inej triede. Na obrázku 4.14 je zobrazená kompozícia, trieda Skladba závislá na triede Album.

Obrázok 4.20: Mapovanie závislosti Každá závislá trieda musí mať práve jedného „vlastníka“. V prípade, že na tejto závislej triede už nie je iná trieda závislá, tak mapovačom môže byť pôvodný vlastník. V opačnom prípade sa trieda Mapovač albumu stará o mapovanie skladieb.

36 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE Zabudovaná hodnota Zabudovaná hodnota (Embedded value ) je označenie vzoru, ktorý mapuje niektoré atribúty objektu do viacerých hodnôt v databáze. Typicky ide o mapovanie časových intervalov a financií.

Obrázok 4.21: Zabudovaná hodnota V príklade na obrázku 4.15 je znázornené mapovanie objektu Zamestnanie do tabuľky Zamestnania. Napr. atribút rozsah je typu DateRange 19 je v tabuľke mapovaný do dvoch časových hodnôt označujúcich začiatok a koniec. Podobne funguje mapovanie typu objektu Money predstavujúceho peniaze.

Serializovaný LOB Vzor Serializovaný LOB (Serialized LOB ) ukladá skupinu objektov do jedného stĺpca databázy serializáciou vo formáte LOB. LOB ( large object ) predstavuje kolekciu binárnych dát, ide o dátový typ používaný v databázach. Často sa nazýva aj BLOB ( Binary Large Object ) a v praxi najčastejšie uchováva obrázky a zvuky. Pojem serializácia značí proces prevodu objektu do jeho sekvenčnej, jednorozmernej podoby.

19 Typ udávajúci veľkosť intervalu medzi dvomi časovými razítkami. 37 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE

Obrázok 4.22: Serializovaný BLOB Na obrázku 4.16 sú objekty označujúce organizačnú štruktúru zákazníka. Firma každého zákazníka má niekoľko oddelení, ktoré sú v hierarchickom usporiadaní. Manipulácia s relačnou schémou, kde by každé oddelenie v stĺpci rodič udržovalo príslušný cudzí kľúč, by bola veľmi zdĺhavá a pomalá. Preto sú tieto hierarchicky usporiadané objekty uložené v tabuľke Zákazníci ako serializované objekty.

4.3.5 Vzory objektovo-relačných mapovacích metadát Tieto vzory (Object-Relational Metadata Mapping Patterns ) mapujú popisné dáta (metadáta) tabuliek v databáze.

Mapovanie metadát Návrhový vzor Mapovanie metadát (Metadata Mapping ) je určený na udržovanie metadát objektovo-relačného mapovania. V tomto prípade je možné si pod pojmom metadáta predstaviť informácie o tom, ktoré atribúty objektov sú mapované na aké stĺpce tabuliek, viď obrázok 4.23.

Obrázok 4.23: Mapovanie metadát

38 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE Program môže tieto metadáta spracovávať dvoma spôsobmi: 1. Generovaním kódu (Code generation ): Program načíta metadáta a vygeneruje kód namapovaných tried, ktorý vyzerá akoby bol napísaný programátorom. 2. Reflexiou ( Reflective programming ): Objekt reaguje na volanie metódy setName tak, že sám vygeneruje vlastné atribúty a metódy.

Dopytovací objekt Podstatou vzoru Dopytovací objekt (Query Object ) je vytváranie SQL dopytov nad databázou.

Obrázok 4.24: Dopytovací objekt Dopytovací objekt je inšpirovaný pôvodným návrhovým vzorom Interpreter. Vytváranie databázových dopytov môže byť lokalizované na jedno miesto programu spravované zvlášť, na rozdiel od samotného dopytovania a získavania dát.

Repozitár Repozitár (Repository ) je sprostredkovateľom medzi doménovými a dátovými mapovačmi, správajúci sa ako kolekcia doménových objektov. Takáto začlenená vrstva minimalizuje duplicitný kód pri dopytovaní. Klient vytvorí objekt Kritérium, ktorým charakterizuje tie parametre objektov, ktoré chce dopytom získať. V prípade obrázku 4.25 chce získať Osoby. Následne je Kritérium poslané Repozitáru ako parameter jeho metódy vyhovuje. Ten sa dopytuje objektu Pamäť o Osoby, ktoré podmienkam vyhovujú a po vyhľadaní sú mu v kolekcii vrátené.

39 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE

Obrázok 4.25: Repozitár

40 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE 4.4 Výhody použitia ORM

Použitie objektovo-relačného mapovania prináša pre programátora a aplikáciu množstvo výhod: • Spôsob prístupu k dátam: K dátam relačnej databázy je pomocou ORM pristupované, akoby sa jednalo o objektové úložisko, vývojár je teda abstrahovaný od fyzického spôsobu uloženia dát. V skutočnosti nemusí nutne ísť o relačnú databázu, dáta môžu byť uložené aj napr. v XML súbore. Výhodou je rovnako aj striktné oddelenie dátovej vrstvy od ostatných vrstiev aplikácie. Práca s objektami reálneho sveta je prirodzenejšia ako práca s množinou prepojených riadkov z databázy. • Nezávislosť na databáze: Aplikácia získa určitú nezávislosť voči databázovému systému, ktorý je možné vymeniť za iný bez veľkých zmien v zdrojovom kóde, ak sa zachová štruktúra mapovania. Toto predstavuje výhodu aj pri vývojových fázach a testovaní. Ak ORM podporuje viacero databáz (a väčšina z nich podporuje), tak je možné aplikáciu vyvíjať a určité časti testovať na inej databáze ako na tej, ktorá bude figurovať v pozícii databázy produkčnej. ORM riadi špecifické vlastnosti databáze, s ktorými programátor nemusí byť oboznámený (napr. spôsob ukladania dátumov, alebo načítavanie len určitého počtu záznamov). • Rýchlosť a cena vývoja: Ak sa vývojár zoznámi s ORM nástrojom a naučí sa ho správne používať, tak je možné za veľkú výhodu označiť zvýšenie produktivity pri písaní softvéru. Vývojár nemusí písať kód starajúci sa o ukladanie, či upravovanie dát v databáze, stačí mu použiť konkrétny príkaz, ktorý toto chovanie popisuje. Okrem zabezpečenia ukladania modifikovaných objektov do databáze, ORM dokáže riešiť aj opačný problém: pri zmene dát v databáze vie zmeniť tieto dáta v objekte. Klasický prístup využívajúci dopytovanie pomocou SQL kódu je procesorovo rýchlejší, ale pre vývojára pracnejší, lebo sa musí zaoberať množstvom réžijného kódu okolo, ktorými riadi vykonávanie SQL dopytov a spracovávanie výsledkov, zároveň musí detailne poznať štruktúru databáze. ORM zdrojový kód pracujúci s databázou je kratší, rýchlejšie napísaný, eliminovaný od veľkého množstva opakujúceho sa kódu a je častokrát kontrolovaný kompilátorom v čase prekladu aplikácie. Chyby v SQL kóde, ktorý býva v zdrojovom kóde uložený ako reťazec sa prejavujú až za behu. Rýchlosť vývoja je samozrejme priamo úmerná jeho cene. • Čistota kódu: Čistý a rýchlo napísaný kód súvisí s predchádzajúcou výhodou. Takýto kód je kratší, čitateľnejší a zameriava sa viac na biznis logiku ako na réžiu pri spracovaní SQL. Kratší a prehľadnejší kód je vhodnejší na refaktorizáciu a lepšie sa udržuje oproti kódu využívajúcom dopytovanie pomocou SQL.

41 KAPITOLA 4: OBJEKTOVO-RELAČNÉ MAPOVANIE 4.5 Nevýhody použitia ORM

• Zníženie výkonu: Z hľadiska výkonu ORM predstavuje ďalšiu vrstvu naviac, ktorá aplikáciu nutne spomalí. Toto znevýhodnenie sa dát eliminovať napr. používaním medzipamäte. Spomalenie predstavujú aj dopyty typu 1+N, keď sú pre daný objekt načítavané súvisiace objekty a ďalšie objekty pre tieto objekty, atď. Toto je dôsledkom načítavania označovaného ako netrpezlivé ( eager ). Riešením je používanie dopytu typu HQL (sekcia 7.3), kde sa špecifikujú objekty, ktoré sa majú načítať, resp. použiť lenivé nahrávanie. ORM väčšinou nie sú vhodné na hromadné vkladanie dát, operácie typu bulk . Praktická časť tejto práce niekoľko ORM z hľadiska výkonu porovnáva v kapitole 8. • Tvorba a udržovanie mapovania: Pre správne fungovanie ORM je dôležité vytvoriť presnú mapovaciu vrstvu, ktorá odpovedá štruktúre tabuliek v relačnej databáze. V prípade rozsiahlych databáz je manuálne vytváranie mapovania pracné, zdĺhavé a je zdrojom rôznych ťažko odhaliteľných chýb. Mnohé pokročilejšie mapovače v sebe obsahujú generátory týchto mapovacích nastavení, ktoré dokážu pracovať automaticky. Problémom môže byť aktualizácia modelu a mapovania podľa databázy, alebo prispôsobenie databázy podľa zmeny v modeli. Pri niektorých ORM, ktoré využívajú nástroje na automatické generovanie mapovania, je nutné tento proces spustiť znovu. • Nejednotný spôsob dopytovania: Mnoho ORM nástrojov používa rôzne dopytovacie jazyky, ktoré sa vývojár musí naučiť. Argument, ktorý za výhodu ORM udáva, že nie je potrebné poznať SQL nie je zrovna vhodný, lebo pre správne pochopenie ORM dopytovacieho jazyka je dôležité poznať SQL a naopak. Mnohé nástroje podporujú dopytovanie pomocou technológie LINQ (podsekcia 5.1.3), ktorej zvládnutie poskytuje vývojárovi možnosť používať rôzne ORM bez potreby učiť sa nový, špecifický dopytovací jazyk. V porovnaní aktuálnych ORM nástrojov v kapitole 6 je podpora LINQ vždy uvedená. • Kontrola nad SQL kódom: ORM by mal generovať efektívne SQL dopyty, čo ale nemusí byť vždy pravidlom. Pri ručnom tvorení SQL príkazov má programátor nad kódom väčšiu kontrolu a má viac možností ako dopyt optimalizovať. Na zistenie vygenerovaných SQL príkazov je možné použiť nástroj ako SQL Server Profiler. • Počiatočná náročnosť: Programátor musí na začiatku venovať čas štúdiu ORM a spôsobu práce s ním, kde patrí vytvorenie príslušného objektového modelu, konfigurácia mapovania a nový spôsob dopytovania dát, resp. vytvárania a aktualizácie dát stávajúcich.

42 Kapitola 5 Platforma .NET a použité databázy

V tejto kapitole budú spomenuté technológie, ktoré sú využité v implementačnej časti práce. 5.1 Platforma .NET

Definícia platformy .NET priamo od jej autora, spoločnosti Microsoft znie:

.NET je neoddeliteľná súčasť mnohých aplikácií bežiacich na OS Windows, ktorým poskytuje bežnú funkcionalitu potrebnú k ich behu. Pre vývojárov .NET predstavuje komplexný a konzistentný programovací model určený k tvorbe aplikácií s vizuálne ohromujúcim užívateľským zážitkom, bezproblémovou a bezpečnou komunikáciou.[32]

Prvá verzia 1.0 pochádza z roku 2002, aktuálna verzia 4.5 z roku 2012. Kód je možné písať v mnohých programovacích jazykoch: C# 20 , VB.NET, F# a ďalších. [33]. Kód sa pri kompilácii prevádza do platformovo nezávislého jazyka CIL ( Common Intermediate Language ) a potom sa spúšťa v rámci CLR ( Common Language Runtime ). CLR je virtuálny stroj pre beh aplikácií, ktorý zaisťuje bezpečnosť, prácu s výnimkami, správu pamäte, komunikáciu, vykresľovanie grafiky, prácu s databázami a súbormi, atď. Ďalšou súčasťou platformy .NET je BCL ( Base Class Libraries ), čo je kolekcia znovu použiteľných typov, ktoré sú s CLR úzko previazané. Je to súbor základných tried, od ktorých môžu ďalšie triedy dediť a tak rozširovať ich funkcionalitu.

5.1.1 ADO.NET Technológia ADO.NET býva niekedy označovaná ako nástupca ADO 21 , skôr ide o ďalší vývojový krok. Je to jeden zo základných komponentov platformy .NET určený pre prístup k databázam. Mimo relačných databáz, je možné pomocou ADO.NET pristupovať k XML dátam, registrom systému Windows a pod. K databázam sa pristupuje pomocou dátových poskytovateľov ( Data Providers), ktorí obsahujú nasledovné komponenty: • Connection : Zabezpečuje pripojenie a komunikáciu s databázou. • Command : Definuje SQL dopyty a príkazy pre prácu s databázou. Command podporuje možnosť pridávania parametrov ( Parameter ). • DataAdapter : Adaptér umožňujúci prácu s dátami aj po odpojení, slúži ako most medzi dátami a objektom DataSet . • DataReader : Umožňuje sekvenčné čítavanie dát z databáze.

20 V práci sa jazyk C# vyskytuje mnohokrát, vždy je možné ho nahradiť jazykom Visual Basic, napr. pri popisoch tvorby modelov jednotlivých ORM nástrojov. 21 ADO ( ActiveX Data Objects ) je technológia Microsoftu z roku 1996 určená pre prístup k dátam. 43 KAPITOLA 5: PLATFORMA .NET A POUŽITÉ DATABÁZY Základní poskytovatelia umožňujú pripojenie k databázam SQL Server a Oracle, ďalší podporujú pripojenie pomocou ODBC 22 a OLE DB 23 . Napr. pripojenie k SQL Serveru umožňuje poskytovateľ z .NET menného priestoru System.Data.SqlClient . Okrem prístupu k skutočným databázam je možné pomocou ADO.NET vytvoriť jednoduchú databázu v pamäti aplikácie s podporou základných (CRUD) operácií. Na uloženie dát sa používa DataSet, ktorý reprezentuje načítanú databázu v pamäti skladajúcu sa z tabuliek ( DataTable ) a vzťahov medzi nimi ( DataRelations ). DataTable je zložená z riadkov ( DataRow ) a stĺpcov ( DataColumn ) a obmedzení ( Constraint ), trieda DataView reprezentuje pohľad na riadky triedy DataTable, ktoré môžu byť napríklad zoradené, alebo filtrované podľa pravidla. [34] Nevýhodou ADO.NET je práca s dátami v plochom usporiadaní do riadkov a stĺpcov a nie v objektovej forme.

5.1.2 WPF WPF označuje technológiu Windows Presentation Foundation , ktorou sa nazýva nová generácia užívateľských rozhraní pre systémy Windows, ide o alternatívu ku klasickému spôsobu tvorby rozhraní pomocou WinForms . WPF je podobná technológii Silverlight určenej pre webové prehliadače. Na rozdiel od Silverlight-u má WPF prístup k plnej množine funkcií frameworku .NET a je priamo určená pre desktopové aplikácie. Plný popis rozdielov je možné nájsť na Internete. [35] Medzi hlavné výhody, ktoré WPF (hlavne oproti WinForms) ponúka patria: • Nezávislosť na rozlíšení zobrazovacieho zariadenia využívaním vektorovej grafiky. • Podpora hardvérovej akcelerácie zobrazovania a podpora multimédií. • Možnosť tvorby bohatých užívateľských rozhraní aj v 3D. • Popis rozhrania pomocou deklaratívneho jazyka XAML (Extensible Application Markup Language ). • Podpora „data binding-u24 “ WPF programátora vedie k používaniu návrhového vzoru MVVM pri tvorbe aplikácie. MVVM značí Model-View-ViewModel , je to istý druh viacvrstvovej architektúry. WPF a MVVM sú použité v testovacej aplikácii popísanej v sekcii 8.1. Ide o stále pomerne mladú technológiu, medzi ktorej nedostatky patrí menšia ponuka doplnkov oproti WinForms a jej celkom značná náročnosť na programátora potrebná k jej plnému porozumeniu. [36]

22 ODBC ( Open Database Connectivity ) je štandardizované API pre prístup k databázam. 23 OLE DB ( Object Linking and Embedding, Database ) je API od Microsoftu, ktoré rozširuje možnosti ODBC. 24 Preložiteľný ako „viazanie dát“, kde je prvok (cieľ - target ) v užívateľskom rozhraní spojený s iným prvkom UI, resp. zdrojom dát ( source ). 44 KAPITOLA 5: PLATFORMA .NET A POUŽITÉ DATABÁZY 5.1.3 LINQ LINQ je skratkou pre Language-Integrated Query a predstavuje rozšírenie aktuálnych jazykov C# 3.0 a Visual Basic 9.0, prvýkrát predstavené vo verzii .NET 3.5. Hlavnou úlohou tejto technológie je unifikované dopytovanie, tvorba, triedenie a spájanie dát z rôznych zdrojov pomocou deklaratívneho zápisu. Projekt Linq bol pôvodne vyvíjaný pre programovací jazyk Cω v rámci projektu Microsoft Research. [37]

Nové prvky jazyka V jazykoch .NET-u sa objavilo množstvo nových prvkov, niektoré z nich priamo využíva LINQ. Uvedené ukážky zdrojového kódu patria jazyku C#, je však možné ich ekvivalenty zapísať aj v jazyku Visual Basic.: • Vytváranie implicitne typových premenných pomocou nového kľúčového slovo var 25 . Premenné je možné deklarovať bez udania typu, ktorý je určený neskôr kompilátorom. Sú stále silne typové a nie je možné im počas ich životnosti priradiť hodnotu iného typu. var n = 1; // n je typu Int32 var s = "linq" ; // s je typu String • Anonymné typy predstavujú funkcionalitu vytvárania nových typov bez predchádzajúcej definície. Využívajú k tomu spomínané kľúčové slovo var. var o = new { first = "foo" , second = "bar" }; • Inicializácia objektov a kolekcií bez volania konštruktoru s možnosťou inicializácie vlastností. // Inicializácia kolekcie spolu s inicializáciou objektov List foos = new List { new Foo { id = 1, name = "bar" }, new Foo { id = 2, name = "bar2" }, }; • Rozširovacie metódy umožňujú „pridávanie“ nových metód do stávajúcich typov bez nutnosti tento typ modifikovať. Ide o syntaktický cukor, 26 pomocou ktorého sa dá vytvorená statická metóda zavolať bez nutnosti používania triedy do ktorej náleží. Prvému parametru rozširovacej metódy musí predchádzať modifikátor this . // Definícia rozširovacej metódy počítajúca druhú mocninu celočíselného parametru public static int Square( this int i) { return i * i; } // Použitie rozširovacej metódy var x = 5.Square();

25 Nejde o kľúčové slovo známe napr. z jazyka JavaScript. 26 Termín syntaktický cukor vymyslel Peter J. Landin a predstavuje doplnok syntaxe programovacieho jazyka, ktorý existuje za účelom lepšej čitateľnosti zdrojového kódu pre programátora. [38] 45 KAPITOLA 5: PLATFORMA .NET A POUŽITÉ DATABÁZY • Lambda výrazy predstavujú určitú formu anonymných metód, pomocou ktorých je možné vytvárať delegátov (čiže ukazatele na funkcie napr. z jazyka C). Lambda výraz používa operátor => na oddelenie vstupných parametrov od tela funkcie a počas kompilácie môže byť skonvertovaný na delegáta, alebo výrazový strom 27 . delegate int del (int i); del triple = x => x * 3; // Vytvorenie lambda výrazu int j = triple(5); // Použitie lambda výrazu

LINQ syntax LINQ prináša množinu rozširovacích metód generickej kolekcie IEnumerable<> , ktoré slúžia práve na tvorbu dopytov nad dátami. Táto množina metód sa nazýva ako štandardné dopytovacie operátory ( Standard Query Operators ) a rozdeľuje jednotlivé operátory do štrnástich kategórií podľa typu operácie akú vykonávajú: • Filtrovanie ( Filter ): Z množiny výsledkov sú vyfiltrované len niektoré. Operátory OfType a Where. • Projekcia ( Projection ): Slúži na transformáciu objektu na nový typ, ktorý je možné následne použiť. Patria sem Select a SelectMany . • Rozdelenie ( Partition ): Operátory Skip , SkipWhile , Take a TakeWhile umožňujú rozdeliť vstupnú sekvenciu na dve menšie bez zmeny poradia jednotlivých elementov. • Spojenie ( Join ): Pomocou operátorov GroupJoin a Join sa dajú spojiť dva zdroje dát do jedného pomocou spoločného objektu. • Zreťazenie ( Concatenation ): Operátor Concat dokáže spojiť dve sekvencie objektov do jednej. • Usporiadanie ( Order ): Tieto operátory slúžia na radenie objektov podľa viacerých vlastností: OrderBy , OrderByDescending , Reverse , ThenBy a ThenByDescending • Zoskupenie ( Group ): Operátory GroupBy a ToLookup umožňujú rozdeliť sekvenciu objektov do skupín podľa nejakého spoločného atribútu. • Množinové operácie ( Set ): Pomocou operátorov Distinct , Except , Intersect a Union je možné uskutočniť bežné množinové operácie. • Konverzia ( Conversion ): Operátory AsEnumerable , AsQueryable , Cast , ToArray , ToDictionary a ToList dokážu zmeniť typ vstupných objektov. • Rovnosť ( Equality ): SequenceEqual slúži na porovnanie dvoch sekvencií objektov. • Prvok ( Element ): Pomocou týchto operátorov sa dá získať jeden prvok zo sekvencie. Patria sem ElementAt, ElementAtOrDefault , First , FirstOrDefault , Last , LastOrDefault , Single a SingleOrDefault . Variant OrDefault získava v prípade neúspechu predvolenú hodnotu.

27 Výrazový strom je dátová štruktúra obsahujúca výrazy (Expressions). Strom je možné vytvoriť v zdrojovom kóde a následne spustiť. Inak povedané je možné s kódom pracovať ako s dátami. 46 KAPITOLA 5: PLATFORMA .NET A POUŽITÉ DATABÁZY • Generovanie ( Generation ): Operátory generovania DefaultIfEmpty , Empty , Range a Repeat vytvárajú nové sekvencie hodnôt. • Kvantifikácia ( Quantifiers ): Vracajú pravdivostnú hodnotu podľa splnenia určenej podmienky všetkých, žiadnych alebo niektorých elementov sekvencie. Operátory All , Any , Contains. • Agregácia ( Aggregation ): Agregačné operátory Aggregate , Average , Count , LongCount , Max , Min a Sum vypočítajú jednu hodnotu zo sekvencie podľa typu agregácie. Parametrom týchto operátorov sú lambda výrazy. Druhý spôsob zápisu sa nazýva „ Query expression syntax “ a využíva nové kľúčové slová, pomocou ktorých je možné nahradiť niektoré štandardné dopytovacie operátory. Patria sem select , from , where , group , into , orderby , join , let a ako parameter vyžadujú časť lambda výrazu. Takto zapísané LINQ dopyty sú čitateľnejšie, nová syntax predstavuje len syntaktický cukor, ktorý je pri kompilácii nahradený štandardnými operátormi. Väčšina z uvedených kľúčových slov má svoj ekvivalent medzi štandardnými operátormi okrem let , ktorý slúži na definovanie dočasnej premennej s oborom platnosti v rámci daného LINQ výrazu, from , ktorý špecifikuje dátový zdroj a into používaný v kombinácii s group .

Príklad použitia oboch spôsobov pre filtrovanie párnych čísiel z poľa, ktoré sú následne zoradené podľa veľkosti: int [] numbers = { 6, 7, 8, 5, 9, 10, 1, 2, 3, 4 };

// Query operátor IEnumerable even = numbers .Where(x => x % 2 == 0) .OrderBy(x => x);

// Query syntax IEnumerable even = from n in numbers where n % 2 == 0 orderby n select n; V skutočnosti sú oba LINQ výrazy kompilátorom transformované do nasledujúceho kódu využívajúceho statické metódy triedy Enumerable: IEnumerable even = Enumerable .OrderBy( Enumerable .Where(numbers, x => x % 2 == 0), x => x); Syntax LINQ je inšpirovaná jazykom SQL. V praxi sa oba spôsoby zápisu často kombinujú, hlavne operácie spájania (join) sú pre človeka lepšie čitateľné v zápise pomocou Query syntaxe. Príklady zápisu dopytov oboma spôsobmi sú v prílohe B. Operátory poskytovateľa LINQ to Objects pracujú nad kolekciou (rozširujú ju), ktorá implementuje rozhranie IEnumerable . Napr. v prípade poskytovateľa LINQ to SQL ide o rozhranie IQueryable . Operátory je možné rozdeliť do dvoch skupín podľa toho, či priamo vyžadujú, alebo nevyžadujú komunikáciu so zdrojom dát. Napr. operátor Where nevyžaduje zdroj dát, iba

47 KAPITOLA 5: PLATFORMA .NET A POUŽITÉ DATABÁZY špecifikuje prvky, cez ktoré sa bude iterovať. Na druhú stranu agregačné operátory ako Max , alebo Min potrebujú komunikovať so zdrojom dát aby okamžite vrátili správny výsledok. Pre vynútenie okamžitého spustenia LINQ výrazu je možné zavolať niektorý z konverzných operátorov ( ToList , ToArray ), lebo štandardná vlastnosť LINQ je, že k spusteniu výrazu príde až v dobe získavania jeho výsledkov a nie v dobe definíce v zdrojovom kóde. Toto chovanie sa nazýva ako „Deffered execution “. Popis všetkých LINQ operátorov je nad rámec tejto práce, viac informácií je možné dohľadať v príslušnej literatúre [38], alebo na Internete. [39] Nasleduje bližšie vysvetlenie len niekoľkých najpoužívanejších operátorov.

Operátor Where Operátor Where slúži na filtrovanie elementov do sekvencie a je deklarovaný nasledovne: public static IEnumerable Where( this IEnumerable source, Func predicate); 28 Ide o statickú metódu, ktorá rozširuje generickú kolekciu IEnumerable. Parametrom metódy je predikát, funkcia s generickým parametrom TSource vracajúca bool . Metóda where vracia generickú kolekciu IEnumerable, ktorá je rovnakého typu ako tá, ktorú rozširuje. Zjednodušene povedané, pomocou metódy Where je možné filtrovať vstupnú sekvenciu podľa definovanej reštriktívnej podmienky.

Operátor Select Select je operátorom projekcie, ktorý vytvára sekvenciu elementov buď zvolením z množiny stávajúcich, alebo vytvorením nových. public static IEnumerable Select( this IEnumerable source, Func selector); 29 Rovnako ako v prípade Where ide o rozširovaciu metódu IEnumerable . Táto metóda operuje na vstupnom type TSource a vracia koleciu typu TResult . Druhým argumentom je selector – delegát metódy. Selector vracia objekt, ktorého jednotlivé prvky pri prechádzaní sú typu TResult (v skutočnosti môžu byť typy TSource a TResult rovnaké, alebo rozdielne). Druhým projekčným operátorom je SelectMany , ktorý dokáže vytvoriť viacero výstupných sekvencií z jednej vstupnej. Operátory Select a Where pracujú podobne ako relácie selekcie a projekcie relačnej alebry (podsekcia 2.2.3).

Operátor GroupBy GroupBy umožňuje zoskupovať výsledky podľa zvoleného kľúča do sekvencie (podobne ako SQL), existuje v siedmych preťažených variantoch. Jednou z nich je:

28 V skutočnosti existuje ešte jedna verzia metódy Where líšiaca sa parametrom predicate obsahujúcom ďalší parameter typu int. 29 Druhá verzia operátora Select obsahuje selector s ďalším celočíselným parametrom určujúcim index vstupnej sekvencie. 48 KAPITOLA 5: PLATFORMA .NET A POUŽITÉ DATABÁZY public static IEnumerable > GroupBy( this IEnumerable source, Func keySelector); Výsledkom je sekvencia skupín (opäť sekvencií implementujúcich rozhranie IGrouping ), kde každá skupina je charakterizovaná odlišným kľúčom.

Operátor Join Join vykonáva spojenie dvoch sekvencií typu TOuter a TInner podľa ich kľúčov do novej výstupnej sekvencie typu TResult . public static IEnumerable Join( this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector); 30 Ukážkové spojenie sekvencií items a orders podľa spoločnej vlastnosti id vyzerá pomocou štandardných operátorov a lambda výrazov takto: var result = items .Join(orders, i => i.id, o => o.id, (i, o) => new { i = i, o = o }) .Select( x => new { id = x.i.id, name = x.i.name, orderDate = x.o.date }); Zápis pomocou Query syntaxe je čitateľnejší a v praxi viac používaný: var result = from i in items join o in orders on i.id equals o.id select new { id = i.id, name = i.name, orderDate = o.date }; Druhým podobným operátorom je GroupJoin (pri použití Query syntaxe ako join .. into ), ktorý je podobný spájaniu LEFT OUTER JOIN známemu z SQL.

Operátor OrderBy OrderBy spolu s OrderByDesceding sú operátory určené k radeniu sekvencií operujúce nad sekvenciou typu IEnumerable , vracajúce sekvenciu typu IOrderedEnumberable . public static IOrderedEnumerable OrderBy( this IEnumerable source, Func keySelector); 31

30 Druhá verzia vyžaduje ako ďalší parameter triedy implementujúcu IEqualityComparer , ktorého metóda Equals určuje rovnosť dvoch vstupných parametrov. 49 KAPITOLA 5: PLATFORMA .NET A POUŽITÉ DATABÁZY Druhým parametrom je metóda keySelector, ktorá určuje kľúč z elementu, podľa ktorého bude sekvencia zoradená. Pre radenie podľa ďalšieho prvku je nutné výsledok zreťaziť s operátormi ThenBy , alebo ThenByDescending , ktoré ako vstupnú sekvenciu akceptujú IOrderedEnumerable .

Prínos a výhody LINQ Značnou výhodou technológie LINQ je jej architektúra, ktorá je navrhnutá tak, aby umožňovala tvorbu vlastných poskytovateľov pre rôzne zdroje dát a tak rozširovala svoju funkcionalitu. Predchádzajúce ukážky kódu patrili poskytovateľovi LINQ to Objects, zvyšní dodávaní poskytovatelia sú LINQ to XML, LINQ to SQL (sekcia 0) a LINQ to DataSet. Ďalší poskytovatelia sú vyvinutí tretími stranami, ako LINQ to Amazon, LINQ to Active Directory a desiatky ďalších. [40]. Pre programátora je tak spôsob získavania dát z rôznych zdrojov značne zjednodušený a unifikovaný. Vďaka integrácii do prostredia .NET sú LINQ výrazy kontrolované kompilátorom a ich tvorba využíva v prípade použitia vývojového prostredia Visual Studio dopĺňanie zdrojového kódu (IntelliSense ), ktoré má veľký vplyv na zvýšenie produktivity. Výrazy LINQ sa dajú skladať tak, že výsledok jedného môže predstavovať zdroj dát pre výraz druhý. Zložité výrazy je vhodné rozdeliť na niekoľko menších a jednoduchších, v ktorých sa lepšie hľadajú prípadné chyby. [38], [51] 5.2 Microsoft SQL Server

SQL Server je produkt firmy Microsoft na poli relačných databázových systémov typu klient – server. Prvýkrát sa na trhu objavil v roku 1989 vo verzii 1.0 pre systém OS/2. Až verzia 4.21 z roku 1993 bola určená pre systém Windows NT a Microsoft na nej pracoval ďalej samostatne bez pomoci iných firiem. Zhruba každé dva až tri roky vychádza nová verzia. Aktuálna je 11.0 z roku 2012 s označením SQL Server 2012 a je použitá v praktickej časti aplikácie, popísanej v sekcii 8.1. SQL Server sa predáva v niekoľkých edíciách, odstupňovaných na cene v závislosti od maximálneho množstva využiteľných procesorov, pamäte a úložného priestoru. K dispozícii je aj Express verzia, ktoré je zdarma s niekoľkými obmedzeniami: Maximálna veľkosť uložených dát je 10 GB a databáza dokáže využiť najviac jeden procesor so štyrmi jadrami a 1 GB operačnej pamäte. Výhodou pri programovaní .NET aplikácii je integrácia do vývojového nástroja Visual Studio a zdarma dodávaný program na správu SQL Server Management Studio. Súčasťou produktu je nástroj SQL Server Profiler, použiteľný pri monitorovaní práce serveru. V prílohe B sú zdrojové kódy zachytených SQL dopytov tak, ako ich vygenerovali jednotlivé ORM nástroje.

31 Druhá verzia OrderBy má ako tretí parameter triedu implementujúcu IComparer , ktorého metóda Compare určuje spôsob akým porovnávať dva vstupné parametre. 50 KAPITOLA 5: PLATFORMA .NET A POUŽITÉ DATABÁZY 5.3 RavenDB

RavenDB je predstaviteľom dokumentovej NoSQL databáze určenej primárne pre aplikácie na platforme .NET. Pre projekty vyvíjané ako open-source je zdarma, v prípade komerčného nasadenia je nutné zakúpiť licenciu, ktorej cena sa odvíja od počtu použitých procesorových jadier. V základe ide o databázu s podporou ACID transakcií (na rozdiel od iných dokumentových databáz [17]), ktorá je v základnej konfigurácii bezpečná ( Safe by default ). RavenDB podporuje horizontálne škálovanie. Nie je potrebná definícia štruktúr, dáta sú ukladané vo formáte JSON, binárne dáta je možné ukladať ako prílohy ( Attachments ). Pre indexovanie dát je použitý open-source projekt Apache Lucene. Indexy sú vytvárané automaticky v pozadí podľa dopytov na databázu, je však doporučené ich definovanie v zdrojovom kóde pomocou LINQ s využitím MapReduce. Databázový server je možné spustiť v rôznych módoch: Ako služba systému Windows, aplikácia pre webový server IIS, súčasť vlastnej .NET aplikácie ( embedded riešenie) a ako konzolová aplikácia. Okrem bohatého API pre platformu .NET a možnosti vytvárať databázové dopyty pomocou LINQ, RavenDB poskytuje HTTP API vyhovujúce REST 32 princípom. Súčasťou databáze je klient slúžiaci na správu databáze, ktorý beží ako Silverlight aplikácia vo webovom prehliadači. [41]

32 REST ( Representational State Transfer ) je jednotné API pre webové aplikácie 51 Kapitola 6 Prehľad ORM nástrojov

Pre platformu .NET sa na trhu nachádzajú desiatky, až stovky ORM nástrojov rôzneho rozsahu a kvality. Patria sem zavedené projekty vyvíjané veľkými firmami, alebo značným množstvom dobrovoľníkov open-source komunity, ale aj malé mikro-mapovače spadajúce pod jedného, dvoch programátorov. Ucelenejší prehľad dostupných nástrojov sa dá nájsť na Wikipédii, roztrieštené príspevky na rôznych internetových fórach. [42] Táto kapitola podáva prehľad dostupných aktívnych a v skrátenej forme aj neaktívnych projektov. Aktívny projekt je uvedený, ak jeho aktuálna verzia bola vydaná v posledných osemnástich mesiacoch 33 . Zaujímavým pozorovaním je fakt, že každý z uvedených open-source neaktívnych projektov je umiestnený na serveroch Sourceforge.net a Codeplex.com, na druhú stranu všetky open-source ORM projekty na serveri Github.com sú aktívne. To vypovedá o atraktivite posledného menovaného systému pre mladé, dynamicky sa vyvíjajúce (nielen ORM) nástroje. 6.1 Aktívne projekty

Pre každý z nasledujúcich projektov sú uvedené základné údaje o verzii, cene a veľmi stručná charakteristika. NuGet balík označuje podporu nástroja v doplnkoch prostredia Visual Studio. V tabuľkách 6.1 a 6.2 sa nachádzajú ďalšie detaily všetkých vymenovaných aktívnych projektov spolu s informáciou, ktoré databázy sú nimi podporované.

Business Logic Toolkit • http://bltoolkit.net • BL Toolkit je open-source sada nástrojov určená k zjednodušeniu vývoja .NET aplikácií (.NET 3.5, 4.0, Silverlight 4 a ).

Castle ActiveRecord • http://www.castleproject.org/projects/activerecord • Ide o open-source implementáciu návrhového vzoru Aktívny záznam (podsekcia 4.3.2). ORM je vybudovaný nad NHibernate (sekcia 7.3), ale na mapovanie nie je potrebné vytvárať XML súbory, stačí použiť atribúty v zdrojovom kóde. Celková práca s NHibernate je prostredníctvom Castle ActiveRecord značne zjednodušená.

Dapper.NET • https://github.com/SamSaffron/dapper-dot-net • Jednoduchý, veľmi rýchly, open-source ORM distribuovaný ako jeden súbor. Bol vyvinutý autormi webu StackOverflow.com, ktorým nevyhovovalo žiadne z dostupných riešení a potrebovali nahradiť LINQ to SQL.

33 Táto práca je písaná v apríli 2013 52 KAPITOLA 6: PREHĽAD ORM NÁSTROJOV DatabaseObjects.NET • http://www.hisystems.com.au/databaseobjects • ORM nástroj pre .NET, ktorý je možné použiť aj pri programovaní v jazyku Visual Basic 6.

DataObjects.NET • http://dataobjects.net • Komerčný nástroj od spoločnosti Xtensive, pomocou ktorého je možné zdarma pristupovať len k dvadsiatim entitám. Dá sa použiť ako ORM, alebo ako framework na vývoj biznis vrstvy (Business Logic Layer) v mnohovrstvových aplikáciách.

Entity Framework • http://msdn.microsoft.com/en-us/data/ef.aspx • ORM vyvinutý spoločnosťou Microsoft, ktorý je od budúcej verzie 6.0 open-source. Ide o doporučený prostriedok pre vývoj akejkoľvek modernej aplikácie založenej na platforme .NET.

EntitySpaces • http://www.entityspaces.net • Komerčný nástroj spoločnosti EntitySpaces, LLC, ktorého zdrojové kódy boli koncom roku 2012 zverejnené a vývoj prenechaný komunite.

Genome • http://www.genom-e.com • ORM produkt viedenskej spoločnosti TechTalk GmbH určený pre enterprise aplikácie.

LightSpeed • http://www.mindscapehq.com/products/lightspeed • Podľa firmy Mindscape, špecializujúcej sa vývoj rôznych komponentov pre .NET, ide o najrýchlejší ORM na svete. V neplatenej verzii je možno použiť osem entít.

LinqConnect • http://www.devart.com/linqconnect • Rýchle, jednoduché riešenie s plnou LINQ podporou od firmy Devart.

LLBLGen Pro • http://www.llblgen.com • Robustný a stabilný komerčný nástroj s vlastným dizajnérom mapovania, ktorý je zdarma pre maximálne osem entít.

53 KAPITOLA 6: PREHĽAD ORM NÁSTROJOV MicroLite • https://github.com/TrevorPilley/MicroLite • Jednoduchý a rýchly open-source ORM nástroj .

NHibernate • http://nhforge.org • Ide o vyspelý ORM nástroj, ktorý vznikol preportovaním z Javy na platformu .NET.

NPA (.NET Persistence API) • http://www.npersistence.org • Open source nástroj založený na JPA z jazyka Java.

OpenAccess ORM • http://www.telerik.com/products/orm.aspx • ORM nástroj od významného dodávateľa UI komponentov, firmy Telerik.

OrmLite • http://www.servicestack.net • Jednoduchý a rýchly ORM nástroj, pracujúci aj v prostredí Mono.

PetaPoco • http://www.toptensoftware.com/petapoco • Jednoduchý a veľmi rýchly ORM zameraný na POCO (Plain Old CLR Object).

Vici CoolStorage • http://viciproject.com/wiki/projects/coolstorage/home • Jednoduchý ORM nástroj podporujúci aj platformu Windows Phone.

XPO (eXpressPersistent Objects) • http://www.devexpress.com/Products/NET/ORM • Výkonný a komerčný ORM nástroj od spoločnosti DevExpress so zabudovaným profilovacím nástrojom určeným k detekcii kódu spôsobujúceho spomalenie aplikácie.

54 KAPITOLA 6: PREHĽAD ORM NÁSTROJOV

SQLServer SQLite MySQL Oracle Firebird SQLCE VistaDB DB2 Informix PostgreSQL Sybase MicrosoftAccess Pervasive

Business Logic Toolkit × × Castle ActiveRecord × × × × × × Dapper.NET × × × × × DatabaseObjects.NET × × × × × DataObjects.NET × × × × × × Entity Framework × × × × × × × × × × EntitySpaces × × × × × × × × × Genome × × × × LightSpeed × × × × × × × LinqConnect × × × × × × LLBLGen Pro × × × × × × × × × MicroLite × × × × NHibernate × × × × × × × × NPA × × × × × × OpenAccess ORM × × × × × × × × × OrmLite × × × × × PetaPoco × × × × × Vici CoolStorage × × × × × XPO × × × × × × × × × × × × Tabuľka 6.1: Podporované databázy jednotlivými ORM Medzi ostatné, menej významné ORM je možno zaradiť nasledujúce: • Catnap (https://github.com/timscott/catnap) • MyBatis (http://blog.mybatis.org) • Gribble ORM (https://github.com/mikeobrien/Gribble) • Insight.Database (https://github.com/jonwagner/Insight.Database) • MonkeyOrm (http://www.monkeyorm.com) • Monocle (https://github.com/christianz/Monocle) • nHydrate (http://www.nhydrate.org) • NPoco (https://github.com/schotime/NPoco) 55 KAPITOLA 6: PREHĽAD ORM NÁSTROJOV • SqlFu (https://github.com/sapiens/SqlFu) • Symbiotic ORM (http://www.frozenelephant.com/symbiotic.html)

Aktuálna Posledná Rok Použitie NuGet Podpora Názov verzia zmena vzniku zdarma balík LINQ Business Logic Toolkit 4.1 04/2013 2005 Áno Nie Áno Castle ActiveRecord 3.2 02/2013 2010 Áno Áno Áno Dapper.NET 1.12 09/2012 2009 Áno Áno Nie DatabaseObjects.NET 5.1.1.0 10/2012 2008 Áno Nie Nie DataObjects.NET 4.6.3 02/2013 2003 Čiastočne Áno Áno Entity Framework 5.0.0 11/2012 2008 Áno Áno Áno EntitySpaces 2012.1.0930 10/2012 2006 Áno Nie Áno Genome 4.2.7 08/2012 2004 Nie Nie Áno LightSpeed 5 03/2013 2007 Čiastočne Nie Áno LinqConnect 4.2.231 04/2013 2010 Nie Nie Áno LLBLGen Pro 4.0 04/2013 2003 Čiastočne Nie Áno MicroLite 3.0.3 03/2013 2012 Áno Áno Nie NHibernate 3.3.3 04/2012 2003 Áno Áno Áno NPA 2.0.15 01/2013 2011 Áno Áno Nie OpenAccess ORM 2013.1.418.2 04/2013 2010 Áno Áno Áno OrmLite 3.9.43 01/2013 2011 Áno Áno Nie PetaPoco 5.0.1 03/2013 2011 Áno Áno Nie Vici CoolStorage 1.5.2.1017 06/2012 2011 Áno Áno Nie XPO v2012 vol2.8 04/2013 2009 Nie Nie Áno Tabuľka 6.2: Detaily ORM nástrojov 6.2 Neaktívne projekty

Neaktívnych projektov je celá rada, na Internete je možné nájsť desiatky ďalších malých ORM nástrojov, ktoré boli častokrát vyvinuté pre osobnú potrebu konkrétneho vývojára. Jednoznačne najúspešnejší, dnes už neaktívny projekt, je LINQ to SQL od Microsoftu, ktorý sa stále používa a je detailne popísaný v sekcii 0. Výber z ďalších, neaktívnych projektov je v nasledujúcom zozname: • BBA Data Objects (http://sourceforge.net/projects/bbadataobject) • BizBlox ORM (http://sourceforge.net/projects/bizblox) • Codus (http://sourceforge.net/projects/codus) • DADO Database Mapper (http://www.dadosolution.com) • DataBlock (http://www.voidsoft.ro/DataBlock) 56 KAPITOLA 6: PREHĽAD ORM NÁSTROJOV • dbFrameIT (http://www.dbframeit.com) • dOOdads Architecture (http://www.mygenerationsoftware.com) • EasyObjects.NET (http://easyobjects.tigris.org) • Gentle.NET Object Persistence Framework (http://boo.codehaus.org) • Habanero (http://sourceforge.net/projects/habanero) • HaterAide ORM (http://hateraide.codeplex.com) • iBATIS (http://ibatis.apache.org) • JC O/R Framework (http://sourceforge.net/projects/jcframework) • .NET Entity Objects (http://neo.sourceforge.net) • NPersist (http://npersist.com) • ODX.NET (http://odx.codeplex.com) • Object Persistent Framework (http://opf3.codeplex.com) • Persistor.NET (http://www.persistor.net) • Puzzle.Npersist (http://puzzlenpersist.codeplex.com) • Signum Engine (http://www.signumframework.com) • Sooda (http://sooda.sourceforge.net) • SubSonic (http://subsonicproject.com) • Wilson ORMapper (https://code.google.com/p/wilsonormapper) • XML DataMapper (http://xmldatamapper.codeplex.com)

57 Kapitola 7 Vybrané ORM nástroje

7.1 Entity Framework

ADO.NET Entity Framework je ORM nástroj od Microsoftu zabezpečujúci vývojárom prístup k rôznym zdrojom dát a predstavuje vylepšenie ADO.NET.

7.1.1 História Entity Framework (ďalej len EF) bol vydaný 34 v auguste 2008 spolu s verziou .NET 3.5 SP1. Vývojárskou komunitou bol prijatý s negatívnou kritikou, vývojárom sa nepozdával smer, ktorým vývoj EF smeroval. [43] O necelé dva roky, v apríli 2010 prišla druhá verzia s označením podľa platformy .NET: EF 4 s nápravami pripomienok svojho predchodcu. Nástupcom bola verzia 4.1, ktorá bola distribuovaná pomocou rozšírenia pre Visual Studio – balíčkovací systém NuGet. Do vydania aktuálnej verzie EF 5 v auguste 2012 sa objavilo niekoľko opráv a vylepšení verzie 4.1. EF 5 bol distribuovaný spolu s .NET 4.5 v júli 2012. Momentálne vývojový tým pracuje na novej verzii EF 6, ktorej alfa verzia je dostupná od decembra 2012.

7.1.2 Cena EF je od prvej verzie súčasťou platformy .NET a jeho použitie je zdarma. V júli 2012 Microsoft prostredníctvom novej organizačnej jednotky Microsoft Open Technologies oznámil, že sprístupňuje zdrojové kódy EF verejnosti ako projekt open-source, takže sa komunita môže podieľať na vývoji a vylepšovaní produktu. [44]

7.1.3 Dokumentácia Oficiálna dokumentácia je tradične veľmi bohato zastúpená na MSDN 35 . Internetový obchod s literatúrou Amazon po zadaní výrazu „Entity Framework “ vracia takmer 2200 výsledkov, treba však podotknúť, že väčšina kníh sa EF venuje iba okrajovo, často ide o knihy primárne zamerané na jazyk C#, SQL Server, LINQ a pod. Na českom a slovenskom trhu je k dispozícii niekoľko kníh, žiadna z nich však momentálne nie je lokalizovaná. Na platforme .NET je EF najrozšírenejší ORM, je doporučený Microsoftom pre všetky nové aplikácie, ktoré nejakým spôsobom pristupujú k relačným databázam.

34 Entity Framework je nazývaný tiež ako LINQ to Entities (umožňuje LINQ dopytovanie voči EF entitám). Bol vyvíjaný súbežne s LINQ to SQL, každý projekt iným týmom. Pôvodne LINQ to SQL nemal byť sprístupnený verejnosti ako finálny produkt, podľa mnohých názorov však EF nebol hotový v čase vydania .NET verzie 3.5. Microsoft tak sprístupnil v tejto verzii .NET-u LINQ to SQL a s prvou verziou EF počkal až do vydania prvého opravného balíčku Service Pack 1 pre .NET 3.5. Následne bol všetok vývoj na LINQ to SQL presmerovaný na EF. 35 MSDN ( Microsoft Developer Network ): Program Microsoftu určený vývojárom, dostupný online na adrese http://msdn.microsoft.com 58 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE K dispozícii je veľké množstvo návodov, blogov, inštruktážnych videí, čo z EF robí ideálny nástroj aj pre začiatočníka.

7.1.4 Podporované databázy Entity Framework poskytuje možnosť práce s viacerými databázovými servermi. Keďže je EF postavený nad ADO.NET, tak podpora databáz závisí od modelu ADO.NET poskytovateľov (viď podsekcia 5.1.1), ktorí sprostredkovávajú databázové operácie. Poskytovatelia sú vytváraní ako produkty tretích strán a musia zvlášť podporovať EF. Nie je teda možné použiť napríklad neaktuálnych poskytovateľov ODBC, takže doposiaľ neexistuje podpora napr. pre databázu Microsoft Access. Zoznam dostupných poskytovateľov je pomerne bohatý, u každého sú uvedené podporované databázy: • Oficiálny poskytovateľ SqlClient (.NET Framework Data Provider for SQL Server) podporuje SQL Server 7.0 a vyššie, vrátane CE od verzie 3.5. • Oracle poskytovateľ ODP.NET (Oracle Data Provider for .NET) podporuje Oracle databázy. • Progress DataDirect Connect je použiteľný do verzie EF 4.2. Podporuje databázy Oracle, DB2 (iSeries), Sybase a SQL Server. • Devart dotConnect podporujúci Oracle 9 a vyššie, MySQL 5 a vyššie, PostgreSQL 8 a vyššie, SQLite verzie 3 a SQL Server od verzie 2000. • Npgsql (.Net Data Provider for Postgresql) podporuje databázu PostgreSQL od verzie 7. • System.Data.SQLite: Obmedzená funkčnosť pre databázu SQLite. • MySQL Connector/NET: Podporuje MySQL 5 a vyššie. • VistaDB Provider pre databázy VistaDB 4 a vyššie. • Synergy/DE Data Provider for .NET pre databázu Synergy. • Firebird ADO.NET Data Provider podporujúci databázy Firebird. • SAP Sybase Adaptive Server Enterprise pre databázu SAP Sybase Adaptive Server Enterprise. • IBM Data Server Provider for .NET pre databázy DB2 a Informix. • Virtuoso ADO.NET 3.5 Data Provider podporujúci Oracle, SQL Server, DB2, Sybase, Ingres, Informix, Progress, MySQL, PostgreSQL a Firebird. Tento poskytovateľ je určený pre .NET 3.5. • SSAS Entity Framework Provider podporujúci Microsoft SQL Server Analysis Services (SSAS). [45]

59 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE 7.1.5 Architektúra a mapovanie Základný stavebný prvok Entity Frameworku, entitný dátový model (EDM – Entity Data Model ) je uložený vo formáte XML v súbore s koncovkou edmx. Entitný model je upravovaný pomocou nástroja The Entity Data Model Designer (ďalej len Designer) v prostredí Visual Studia. Skladá sa z troch metasúborov, ktoré architektúru modelu vyjadrujú vo vrstvách abstrakcie, viď obrázok 7.1. • CSDL ( Conceptual Schema Definition Language ): Konceptuálna vrstva, nazývaná tiež ako vrstva obchodnej logiky, obsahujuje entity (triedy obchodnej logiky) a vzťahy medzi nimi. Programátorom napísaný kód aplikácie vie iba o tejto vrstve, o ďalších dvoch nasledujúcich nie. • SSDL ( Store Schema Definition Language ): Databázová, resp. logická vrstva popisujúca databázovú štruktúru, ktorá je vygenerovaná na základe konceptuálneho modelu, alebo už existujúcej databázy. Popis obsahuje informácie o tabuľkách, ich stĺpcoch a dátových typoch, vzťahoch medzi tabuľkami a o uložených databázových procedúrach. • MSL ( Mapping Specification Language ): Mapovanie spájajúce obe dve predchádzajúce vrstvy.

Obrázok 7.1: Entity Framework architektúra [45] 60 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE Kontext Do konceptuálnej vrstvy patrí aj kód v jazyku C#, ktorý obsahuje kontext spolu s triedami popisujúcimi jednotlivé entity. Kontext je charakterizovaný triedami ObjectContext a DbContext . DbContext sa objavil v EF 4.1, obaľuje ObjectContext , je jeho zjednodušenou alternatívou a obsahuje špecifické API, ktoré je jednoduchšie na používanie ( Productivity Improvements API ) v porovnaní s API ObjectContext-u. Umožňuje prístup k tvorbe modelu nazvaný Code First. ObjectContext je v EF však zachovaný z dôvodu spätnej kompatibility. V zdrojovom kóde to je ústredný objekt pre komunikáciu s databázou, dá sa na neho nahliadať ako na session. Obsahuje množiny entít v kolekciách DbSet (resp. ObjectSet ), ktoré slúžia na CRUD operácie. Každý načítaný objekt je uchovávaný v medzipamäti kontextu, ktorý je informovaný o všetkých zmenách vlastností. Niekedy sa kontext nazýva ako EntityContainer a reprezentuje návrhové vzory Pracovná jednotka a Repozitár (podsekcie 4.3.3 a 4.3.4).

Entity Entita reprezentuje inštanciu objektu v entitno-dátovom modeli, kde je nazvaný ako Entity Type. Je to základný stavebný kameň konceptuálnej vrstvy. Entity obsahujú vlastnosti (Properties ), rovnakého významu ako vlastnosti v objektoch. Vlastnosti sú plne typové a môžu byť skalárne (obsahujú dáta), navigačné (slúžia na vytváranie väzieb s inými entitami), alebo komplexné (niekoľko skalárnych vlastností). Výhodou navigačných vlastností je, že pri správne nadefinovanom modeli a správne vytvorenom LINQ dopyte nie je nutné vôbec používať operátory spájania. Entity v EF môžu byť viacerých typov: • EntityObject: Sú to entity vygenerované z modelu, ktoré dedia od objektu EntityObject a sú silne závislé od EF. • POCO (Plain Old CLR Object ): Sú opakom EntityObject entít. Nie sú závislé na EF, predstavujú jednoduché bežné triedy platformy .NET. • POCO Proxy: Sú špeciálne POCO entity s prívlastkom „ Proxy “, ktoré spĺňajú určité podmienky: Sú verejné, je možné z nich dediť, nie sú abstraktné a konštruktor je bez parametrov. Navigačné vlastnosti musia byť verejné a virtuálne a trieda entity nemôže implementovať rozhrania IEntityWithChangeTracker alebo IEntityWithRelationships . Hlavný rozdiel od obyčajných POCO entít je v spôsobe ukladania do databáze. • Typ Self-Tracking : Entity sú využiteľné vo viacvrstvovom návrhu aplikácie, lebo dokážu sami sledovať zmeny vo svojich vlastnostiach vďaka implementácii rozhraní IObjectWithChangeTracker a INotifyPropertyChanged .

Asociácie Väzby medzi entitami sa nazývajú asociácie ( Associtations ), sú charakterizované násobnosťou. Asociácie môžu byť typu:

61 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE • Asociácia cudzieho kľúča: Medzi entitami a následne tabuľkami v databáze musí byť definovaný cudzí kľúč. • Nezávislá asociácia ( Independent association ): Cudzí kľúč v databázovom modeli chýba, vzťah je definovaný ďalším objektom, ktorý spravuje Object State Manager . Podporované násobnosti väzieb medzi entitami sú 1:1, 1:N, M:N, namiesto násobnosti jedna, je podporovaná aj násobnosť 0..1 (nula alebo jedna). Pri modelovaní násobnosti typu 1:1 obsahuje prvá entita vlastnosť typu druhej entity. Pri násobnosti 1:N prvá entita obsahuje vlastnosť typu EntityCollection< typ >, kde typ odpovedá druhej entite. Je použitý návrhový vzor Mapovanie cudzím kľúčom. Pri násobnosti M:N je použitý vzor Mapovanie asociačnou tabuľkou, ktorú však Designer EDM nezobrazuje. Entity medzi sebou môžu vytvárať aj ďalšie vzťahy bez ohľadu na väzby v databázovej schéme.

Poskytovatelia pripojenia S databázou EF komunikuje prostredníctvom databázových poskytovateľov spomínaných v predchádzajúcej podsekcii 7.1.4, ktorí rozširujú schopnosti a funkcionalitu štandardných ADO.NET poskytovateľov. Špecializovaní poskytovatelia sa nazývajú EntityClient Data Providers . Ich zodpovednosťou je prevod dopytov vo formáte Entity SQL , resp. LINQ to Entities (sú spomínané v nasledujúcej podsekcii) do SQL.

ObjectServices Nad poskytovateľmi je komponent nazvaný ObjectServices , ktorý transformuje dáta získané z databázy do objektovej formy. Hlavnou úlohou ObjectServices je práca s dátami (načítanie a ukladanie objektov do databáze), udržovanie informácií o objektoch, správa medzipamäte, lenivé nahrávanie. Sem patria spomínane kontexty ( DbContext a ObjectContext ). Manipulácia s entitami môže nastať v rámci jedného kontextu, ide o pripojený variant (Connected Scenario ). Druhý variant je odpojený (Disconnected Scenario ), vtedy je entita načítaná v rámci jedného kontextu a v rámci ďalšieho je nejakým spôsobom modifikovaná a uložená naspäť do databázy. V tomto prípade je potrebné entitu do nového kontextu pripojiť pomocou metódy Attach() .

Spôsoby práce s EF Existuju tri hlavné spôsoby práce ( Workflows ) s EF: • Model First : Prvý je vytvorený konceptuálny model v nástroji Designer a na jeho základe je vytvorená databáza. Zdrojový kód tried je tiež vygenerovaný podľa modelu. • Database First : Z existujúcej databáze je reverzným inžinierstvom vygenerovaný EDM, ďalej je možné ho upravovať. Stačí si zvoliť databázové tabuľky, uložené procedúry. Zdrojový kód tried je vygenerovaný podľa modelu. • Code First : Najprv sú definované triedy, nazývané POCO, z nich je vygenerovaný entitný model a databáza. K priebežnému vývoji modelu je možné použiť techniku

62 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE migrácií ( Migrations ) od verzie EF 4.3. V prípade existujúcej databáze je pomocou kódu vytvorený model a mapovanie.

Vo väčšine prípadov je mapovanie medzi oboma modelmi v pomere 1:1, je ale možné mapovať jednu entitu na viacero tabuliek, resp. viacero entít na jednu tabuľku. Mapovacia vrstva je teda veľmi flexibilná.

7.1.6 Použitie V EF je možné dopytovať dáta dvoma spôsobmi: • Entity SQL: Je to určitá forma SQL jazyka zameraná priamo na entity, použiteľná len na načítavanie dát a nie na manipuláciu s nimi. Od SQL sa líši hlavne tým, že podporuje dedičnosť a vzťahy z EDM, takže nie je nutné používať operácie spájania. Návratová hodnota získaných dát je ObjectQuery , napríklad načítanie objektov Supplier s ID menším ako desať je v Entity SQL zapísané nasledovne: var queryString = "SELECT VALUE s " + "FROM Suppliers AS s " + "WHERE s.SupplierID < 10" ; ObjectQuery suppliers = context.CreateQuery< Supplier >(queryString); Výhodu oproti LINQ to Entities predstavuje pri tvorbe pokročilých komplexných dopytov, ktoré sú častokrát skladané dynamicky podľa vstupných parametrov, napríklad pri tvorbe rôznych reportov. Entity SQL podporuje dopyty s parametrami a podobne ako pri ADO.NET-e je možné získať tok dát, namiesto vytvárania jednotlivých objektov. Po vytvorení Entity SQL dopytu je vygenerovaný virtuálny vyhodnocovací plán vzhľadom na konceptuálny model. Pomocou mapovania sa preloží do plánu vzhľadom na schému databázy. Následne je prevedený do SQL a dáta sú získané. Pri vývoji EF bolo Entity SQL primárnym spôsobom určeným k dopytovaniu dát, LINQ bolo do EF adoptované neskôr, po predstavení technológie LINQ to SQL. • LINQ to Entities: Pre manipuláciu s dátami sa využíva jazykové rozšírenie LINQ popisované v podsekcii 5.1.3. Pre Entity Framework sa poskytovateľ nazýva LINQ to Entities, podobne ako poskytovatelia LINQ to XML alebo LINQ to SQL. LINQ výrazy sú transformované do výrazových stromov a následne spustené voči kontextu. Predchádzajúci Entity SQL výraz na získavanie objektov Supplier je možné pomocou LINQ to Entites zapísať takto: IQueryable suppliers = from s in context.Suppliers where s.SupplierID < 10 select s; Dáta sú získavané z objeku DbContext , nie je nutné vytvárať LINQ dopyt napr. pre získanie mien všetkých objektov Supplier s množiny DbSet :

63 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE foreach (var supplier in context.Suppliers) { Console .WriteLine(supplier.ContactName); } V tomto prípade bude databáza požiadaná o dáta pri každej iterácii, čo nie je výhodné z hľadiska výkonu. Je vhodné načítať potrebné dáta do pamäte naraz napríklad pomocou metódy ToList() a iteráciu vykonať vzhľadom na tieto dáta. Pre získanie všetkých dát z databázy do lokálnej pamäte je možné použiť metódu Load() . Lokálne, už načítané dáta je možné získavať z vlastnosti Local príslušnej množiny DbSet , napr. počet lokálne načítaných objektov Supplier: var count = context.Suppliers.Local.Count; Lokálne uložené objekty sú v kolekcii ObservableCollection , ktorá dokáže oznamovať zmenu svojho obsahu príslušnou udalosťou, toto chovanie je dôležité pri viazaní (binding, spomínaný pre WPF v podsekcii 5.1.2) dát. Dopytovanie databázy a lokálnych objektov sa líši použitým poskytovateľom. Pri databáze ide o LINQ to Entities, pri lokálnych objektoch sa využíva LINQ to Objects. Medzi nimi môžu byť drobné rozdiely, napr. pri porovnávaní reťazcov, ktoré v databázach nemusí rozlišovať veľké a malé písmená, pri objektoch .NET-u však áno. LINQ to Entities plne podporuje všetky operátory technológie LINQ vrátane agregácií, spájania, radenia. Základné nastavenie získavania dát využíva lenivé nahrávanie prostredníctvom vzoru Virtuálny prostredník, ktorý je spomínaný v podsekcii 4.3.3. Dáta je možné načítavať aj netrpezlivo (Eager Loading ), keď sú pomocou metódy Include() označené pridružené objekty, ktoré sa majú načítať spolu s hlavnými. Posledným spôsobom načítavania je explicitné ( Explicit Loading ), ktoré sa podobá na lenivé, pridružené dáta je však nutné načítať ručne, nenačítavajú sa automaticky. Pre pridávanie, zmenu a mazanie entít je nutné použiť LINQ to Entities: Stačí vytvoriť príslušnú entitu, resp. načítanú entitu zmeniť a dáta do databázy odoslať pomocou metódy kontextu SaveChanges() . Pre odstránenie entity je potreba zavolať metódu Remove() príslušného DbSet -u. LINQ výrazy nie je nutné ručne kompilovať s cieľom dosiahnutia lepšieho výkonu pri opakovanom volaní. Od verzie EF 5.0 je automatická kompilácia zapnutá ako východzie nastavenie, toto chovanie je možné vypnúť. [47] Okrem spomínaných dvoch spôsobov je možné použiť bežný SQL kód. Pri získavaní dát sa musí návratová hodnota dopytu zhodovať s typom DbSet , využitie SQL kódu je výhodné pri operáciách vkladania, zmien a odstraňovania riadkov z databáze. Pri použití postupu Code First je možné niektoré kontrolné mechanizmy zapísať v zdrojovom kóde pomocou anotácií, resp. za použitia tzv. Fluent API. Sem patria kontroly typu maximálna dĺžka reťazca, alebo možnosť nastaviť vlastnosť entity na hodnotu typu null. Viac možností prináša DbContext a rozhranie nazvané Validation API, pomocou ktorého je možné vytvárať pokročilejšie kontroly.

64 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE Novinky v EF 5.0 V poslednej verzii EF 5.0 sa objavilo niekoľko noviniek a vylepšení: • Podpora typu Enum , jednotlivé hodnoty sú uchovávané v databáze. • Podpora priestorového ( Spatial ) dátového typu, určenému k uchovávaniu súradníc na Zemi ( DbGeography ) a v priestore ( DbGeometry ). • Už spomenuté automatické kompilovanie LINQ výrazov. • Podpora databázových funkcií vracajúcich výsledky vo forme tabuľky, ktoré je možné ďalej použiť v LINQ výrazoch. • Designer EDM modelu dokáže zobraziť model v niekoľkých diagramoch naraz a jednotlivé entity je možné odlíšiť farebne. [48], [49]

65 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE 7.2 LINQ to SQL

LINQ to SQL je prvým ORM nástrojom Microsoftu, využívajúcim jazykové rozšírenie LINQ k získavaniu dát z relačnej databázy SQL Server. LINQ to SQL je teda len jedným z ďalších rozšírení, podobne ako LINQ to Objects alebo LINQ to XML. Viac o samotnej technológii LINQ je v podsekcii 5.1.3.

7.2.1 História LINQ bolo predstavené na konci roku 2007 spolu s verziou .NET 3.5. História siaha do roku 2003, kedy pôvodným zámerom programátorov Microsoftu nebolo vytvorenie ORM, malo ísť o vývoj doplnku jazyka, ktorý bude podporovať prácu s výrazovými stromami a SQL dopytovaním databázy. Matt Warren – jeden z vývojárov, ktorý pracoval na vývoji LINQ to SQL, pôvodne chcel túto funkcionalitu implementovať do nasledujúcej verzie nástroja ObjectSpaces. Dopyty do databázy nemali byť uložené v zdrojovom kóde ako textové reťazce, malo ísť o silne typové dopytovacie stromy generované kompilátorom. [50] Microsoft v tej dobe smeroval mnoho zdrojov do vývoja WinFS 36 , ku ktorému sa pripojil aj projekt ObjectSpaces. Po tomto spojení interne chýbal jednoduchý dopytovací nástroj. Neskôr bol vývoj WinFS zrušený, nástroj ObjectSpaces nebol v stave aby sa mohol stať súčasťou .NET 2.0. Autori LINQ pracovali na doplnku, ktorý sa dá nazvať ako falošné ORM, nemalo ísť pôvodne o finálny produkt, ale o vnútorne používanú súčasť iných projektov. Nakoniec bolo v mene LINQ interne rozhodnuté, že z LINQ to SQL sa stane funkčný ORM nástroj zameraný na SQL Server. V roku 2008 Microsoft oznámil, že ukončuje ďalší vývoj LINQ to SQL a zameria sa hlavne na Entity Framework.

7.2.2 Cena LINQ to SQL je automatickou súčasťou verzie .NET 3.5, je zdarma aj pre komerčné použitie.

7.2.3 Dokumentácia Jadrom LINQ to SQL je práve LINQ, ktorého dokumentácie je veľmi bohatá. Existujú stovky kníh zaoberajúce sa LINQ, väčšina z nich popisuje v neskorších kapitolách LINQ to SQL, LINQ to XML a pod. Na Internete je tiež možné nájsť množstvo návodov, postupov a príspevkov vo fórach.

7.2.4 Podporované databázy Je podporovaný iba databázový systém Microsoft SQL Server od verzie 2000 vyššie. Okrem neho je možné LINQ to SQL využiť aj v spolupráci s databázou Microsoft Access.

36 WinFS (Windows Future Storage) zrušený súborový systém pôvodne plánovaný pre Windows Vista, ktorý bol založený na relačom spôsobe ukladania dát. 66 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE 7.2.5 Architektúra a mapovanie

Tvorba modelu Vytvorenie modelu databáze je jednoduché prostredníctvom nástroja Designer, ktorý je súčasťou prostredia Visual Studio od verzie 2008. Designer podporuje vytvorenie modelu existujúcej relačnej databázy, stačí presunúť databázové tabuľky pomocou myši na jeho plochu. Príde k automatickému vytvoreniu entitných tried a vzťahov medzi nimi, ktoré odzrkadľujú použitie cudzích kľúčov medzi tabuľkami, podporované násobnosti sú 1:1 a 1:N. V literatúre sa uvádza názov entita (Entity), ale aj entitná trieda (Entity Class). Entita bude chápaná ako viditeľný objekt v nástroji Designer, resp. inštancia entitnej triedy, entitná trieda ako vygenerovaný zdrojový kód popisujúci entitu. Tabuľky a stĺpce sú mapované na objekty (inštancie entitných tried) s atribútmi, pri zmene tabuliek je nutné príslušné entity z nástroja Designer ručne odstrániť a pridať znovu. Pri uložení súboru s entitami Visual Studio vygeneruje zdrojové kódy modelu (entitných tried), ktorý sa fyzicky skladá z troch súborov s rovnakým názvom, ale inou koncovkou: • Model.dbml: Je to XML súbor obsahujúci pripojovací reťazec do databáze, zoznam uložených tabuliek a ich stĺpcov a základné informácie o databázových procedúrach. • Model.dbml.layout: Znovu XML súbor s informáciami o rozmiestnení entít pre nástroj Designer. • Model.designer.cs: Obsahuje zdrojový kód triedy ModelDataContext , ktorá obsahuje mapovanie medzi tabuľkami a objektami. V prípade použitia jazyka Visual Basic by mal tento súbor názov Model.designer.vb. Ak je zvolený názov modelu napr. „PV“, tak by boli jednotlivé pomenovania analogicky iné (PV.dbml, PV.dbml.layout, PV.designer.cs, PVDataContext ). Okrem nástroja Designer je na tvorbu modelu možné použiť aj utilitu SQLMetal. Mapovanie je možné vytvoriť aj ručne editáciou zdrojového kódu, potrebné detaily je nutné zapísať pomocou atribútov, napr. jednoduchá tabuľka s dvomi stĺpcami, kde je jeden z nich primárny kľúč, je zapísaná v zdrojovom kóde ako entitná trieda nasledovne: [Table(Name = "Customers" )] public class Customer { [Column(IsPrimaryKey = true )] public string CustomerID; [Column] public string City; }

Kontext Objekt DataContext je hlavný riadiaci objekt pri použití LINQ to SQL, uchováva parametre slúžiace k pripojeniu do databáze a jeho použitie je veľmi podobné použitiu objektu Conection z ADO.NET.

67 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE Hlavnou úlohou DataContextu je preklad LINQ výrazov na SQL kód a získavanie dát, ktoré následne transformuje na objekty. Je zodpovedný za lenivé nahrávanie, sledovanie zmien objektov, ukladanie dát do medzipamäte. Pre správu a uchovávanie identít objektov je využitý princíp návrhového vzoru Mapa identity (podsekcia 4.3.3). Po načítaní riadku z databáze je zapísaný záznam v tabuľke identít podľa primárneho kľúča a je vytvorený nový objekt. Ak je ten istý riadok načítaný znovu, tak je aplikácií vrátená rovnaká inštancia objektu. V prípade zmeny riadku mimo aplikáciu je táto zmena zachytená pri ukladaní objektu (funkcia SubmitChanges() ) a LINQ to SQL nové dáta zahodí. Je to spôsob akým zabezpečuje integritu dát. Pri zapisovaní do databáze môže nastať konflikt ak sa aplikácia pokúsi aktualizovať dáta objektu, pričom niektoré jeho hodnoty už boli zmenené od doby, keď bol tento objekt z databázy načítaný. Pri podozrení na konflikt sa dáta objektu načítajú znovu, sú porovnané s pôvodnými hodnotami a rozhodne sa, či o konflikt naozaj ide. Ak je rozhodnutie kladné, tak nastane príslušná výnimka a je na programátorovi aby túto situáciu vyriešil. Je možné ponechať objektu pôvodné hodnoty, aktualizovať ho s novými hodnotami, alebo zmeny zjednotiť. Pri zápise do databáze je využitý vzor Pracovná jednotka (podsekcia 4.3.3), zmeny nastanú hromadne po zavolaní funkcie SubmitChanges() . Ak tabuľka neobsahuje primárny kľúč, tak je možné dáta získať, ale nie je možné ich zmeniť.

Entity Každá vygenerovaná entitná trieda dátového kontextu implementuje rozhrania INotifyPropertyChanging a INotifyPropertyChanged . Entitné triedy je možné rozšíriť o vlastnú biznis logiku prostredníctvom parciálnych metód a ich dedičnosť je vybudovaná podľa návrhového vzoru Dedičnosť jednej tabuľky (Single table inheritance – podsekcia 4.3.4). Rovnako ako Entity Framework, aj LINQ to SQL využíva ADO.NET na komunikáciu s databázou.

7.2.6 Použitie Pre prístup k dátam sa používa mnohokrát spomínaná technológia LINQ. Použitie je jednoduché: stačí vytvoriť dátový kontext ( DataContext ) a pomocou LINQ z neho získať dáta. Výsledky implementujú rozhranie IQueryable , čo je hlavný rozdiel od LINQ to Objects, ktorého výsledky implementujú IEnumerable. Ďalším významným rozdielom je transformácia LINQ výrazu do SQL dopytu pomocou výrazových stromov, vďaka ktorým je SQL dopyt vygenerovaný optimálne a dáta sú pomocou neho získané naraz. Z hľadiska syntaktických konštrukcíí však rozdiel medzi LINQ to SQL a LINQ to Objects nie je. LINQ to SQL podporuje transakcie, pohľady a databázové procedúry a poskytuje integrovanú validáciu dát vlastnú biznis logiku v dátovom modeli. Východzie chovanie umožňuje dáta získavať lenivým spôsobom, až v momente potreby. Okamžité vykonanie

68 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE databázovej operácie v momente definície LINQ dopyty zabezpečí metóda ToList() alebo ToArray(). V prípade potreby je možné špecifikovať načítanie ďalších dát pomocou objektu DataShape a nastavenia LoadWith , napr. pri načítaní dát zákazníka načítať aj jeho objednávky: DataShape ds = new DataShape (); ds.LoadWith< Customer >(c => c.Orders); db.Shape = ds; var q = from c in db.Customers where c.City == "London" select c; LINQ dopyty sa dajú skompilovať vopred a tak zvýšiť výkon aplikácie. Toto chovanie je doporučené pre dopyty, ktoré sa častejšie opakujú. V testovacej aplikácii bolo toto zrýchlenie odmerané, viď graf 8.1. LINQ to SQL umožňuje vytvárať nove databázy, naprogramovaná aplikácia sa môže sama nainštalovať na poskytnutý databázový server. Okrem dopytovania pomocou LINQ je možné vykonať klasický SQL dopyt a dáta získať v podobe objektov. Výhodou oproti iným ORM je priama integrácia do Visual Studia a dobrá podpora SQL Serveru vrátane databázových procedúr. Okrem nástroja Designer je na tvorbu modelu možné použiť aj konzolovú utilitu SQLMetal, resp. ich vhodne kombinovať: model vytvoriť pomocou SQLMetal a jednotlivé úpravy vykonať pomocou nástroja Designer. Akýkoľvek databázový dopyt (aj viacnásobné spájanie tabuliek) je možné zapísať pomocou LINQ, sú však situácie, keď je použitie LINQ to SQL nevhodné. Niekedy je potreba vytvárať v databázovom dopyte dočasné tabuľky, plniť ich dátami a ďalej s nimi manipulovať, takéto chovanie nie je pomocou LINQ to SQL možné. Rovnako aj pri hromadnom vkladaní záznamov je výhodnejšie použiť priame volanie SQL dopytu. [51]

69 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE 7.3 NHibernate

NHibernate je vyspelý open-source ORM nástroj pre platformu .NET, ktorý vznikol na základoch ORM Hibernate z platformy Java.

7.3.1 História Projekt Hibernate bol vytvorený v roku 2001 ako ORM pre platformu Java, neskôr na jeho základoch bol v roku 2003 postavený projekt NHibernate. Vývoj bol do roku 2006 zastrešovaný spoločnosťou Red Hat (do roku 2005 to bola spoločnosť JBoss, ktorá sa neskôr stala divíziou Red Hat-u). Dnes je NHibernate vyvíjaný open-source komunitou. Aktuálna verzia je 3.3.3 z apríla roku 2012, verzia 3 bola vydaná koncom roka 2010, verzia 2 je z leta 2008. Vývoj je aktívny, každý mesiac na projekte vznikne množstvo zmien, podľa štatistík serveru Ohloh bola za posledný rok operácia commit (potvrdenie zmien v pracovnej kópii projektu v systéme na vytváranie verzií zdrojového kódu – SVN, Git) vykonaná 600-krát. [52]

7.3.2 Cena NHibernate je zdarma, je vyvíjaný komunitou ako open-source. Licencia je typu LGLP a všetky zdrojové kódy sú verejne prístupné.

7.3.3 Dokumentácia Je to jeden za najviac používaných ORM na platforme .NET, k dispozícii sú desiatky knižných publikácií (v českom jazyku len jeden preklad). Na oficiálnom webe projektu sú odkazy na niekoľko Google Groups v rôznych jazykoch (bez češtiny a slovenčiny). Popularita medzi vývojármi je pomerne značná, na webe StackOverflow sa momentálne nachádza takmer 14 000 otázok týkajúcich sa priamo NHibernate.

7.3.4 Podporované databázy Sú podporované najpoužívanejšie relačné databázy, primárne je produkt testovaný na databáze SQL Server. Pri konfigurácii NHibernate by sa mal nastaviť správny dialekt použitia, ktorý umožní využívať špecifické rysy zvolenej databázy. • SQL Server 2000 – 2008 a edícia Compact, verzia 2012 funguje s dialektom 2008. • Microsoft Access • Oracle 9-11 s poskytovateľmi ODP.NET a OracleClient. • PostgreSQL 7.4 a vyššia s poskytovateľom Npgsql. • MySQL od verzie 3 s poskytovateľom Connector/Net. • DB2 a DB2 for iSeries (OS/400). • SQLite verzia 3 pomocou poskytovateľa ADO.NET 2.0 Provider for SQLite. • Firebird od verzie 1.5.3 prostredníctvom Firebird.NET.

70 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE 7.3.5 Architektúra a mapovanie

Komponenty NHibernate NHibernate je veľmi flexibilný nástroj a poskytuje niekoľko spôsobov konfigurácie a prístupu do databázy. Medzi základné a najdôležitejšie komponenty patria: • Rozhranie ISession : Objektová reprezentácia komunikácie medzi aplikáciou a databázou, obaľuje ADO.NET pripojenie. Udržuje medzipamäť prvej úrovne, čo je kolekcia objektov týkajúcich sa jednej Pracovnej jednotky. Ponúka základné funkcie na hľadanie, aktualizáciu, mazanie dát. Session je vytváraná veľmi často, pri každom požiadavku na akúkoľvek databázovú operáciu, nie je možné ju zdieľať v rámci viacerých vlákien programu. • Rozhranie ISessionFactory : SessionFactory je objekt skompilovaných mapovaní patriaci jednej databáze. Implementuje návrhový vzor Továreň ( Factory ), slúži na vytváranie objektov Session . SessionFactory môže voliteľne figurovať v pozícii medzipamäte druhej úrovne. Typicky existuje jedna SessionFactory v rámci celej aplikácie. • Configuration: Objekt udržujúci konfiguráciu NHibernate. • Rozhranie ITransaction : Funkcionalita používaná aplikáciou k špecifikácii atomických operácií. Umožňuje správu transakcií jednotným spôsobom, abstrahuje aplikáciu od používania transakcií ADO.NET. • Rozhranie ITransactionFactory : Objekt vytvárajúci inštancie transakcií. • ConnectionProvider: Objekt vytvárajúci databázové spojenia, abstrahuje od špecifických implementácii DbConnection a DbCommand .

Tvorba mapovania NHibernate vo východzej konfigurácii nedisponuje nástrojom, ktorým by bolo možné zautomatizovať proces tvorby modelu, resp. vytvorenie mapovania na základe existujúcej databázy. Programy tretích strán, napr. Entity Developer od firmy Devart, alebo Designer z ORM LLBLGen Pro (sekcia 0) od firmy Solutions Design vytvorenie mapovania pre NHibernate podporujú, takže tvorba modelu podľa značného počtu tabuliek z databázy nemusí nutne predstavovať zdĺhavú a manuálnu prácu. Pre menšie projekty je manuálna tvorba modelu a mapovania rýchla. Pre každú tabuľku je potrebné vytvoriť vlastnú triedu, ktorou bude charakterizovaná. NHibernate podporuje POCO ( Plain Ordinary CLR Objects ) objekty, definované pomocou jazyka C# v súbore s koncovkou „cs“. NHibernate vyžaduje konštruktor bez akýchkoľvek parametrov. Ukážková definícia POCO objektu (Shipper z databázy Northwind): public partial class Shipper { public Shipper() { this .Orders = new Iesi.Collections.HashedSet(); } public virtual int ShipperID { get ; set ; } public virtual string CompanyName { get ; set ; }

71 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE public virtual string Phone { get ; set ; } public virtual Iesi.Collections.ISet Orders { get ; set ; } } Množina zakázok Orders je typu Iesi.Collections.ISet , ktorý predstavuje kolekciu unikátnych objektov (alternatíva k typu „Set“ z Javy). Druhou, ideálnejšou voľbou je použiť generický typ ICollection s využitím funkcie AsSet() a vyhnúť sa tak manuálnemu pretypovávaniu. Mapovanie tried na tabuľku je definované v XML súbore s koncovkou „hbm.xml“. Alternatívu k XML mapovaniu predstavuje open-source doplnok Fluent NHibernate, ktorý umožňuje definovať mapovanie v zdrojovom kóde jazyka, ktorý je kompilovaný pred spustením aplikácie. Tento spôsob zápisu je elegantnejší a čitateľnejší. Porovnanie dvoch ekvivalentných mapovaní (vľavo XML, vpravo Fluent) objektu Shipper z predchádajúceho príkladu: public class ShipperMap : assembly ="NHibernateTool" { namespace ="NHibernateTool" public ShipperMap() { xmlns ="urn:nhibernate-mapping-2.2"> Schema( @"dbo" ); Id(x => x.ShipperID) .CustomType( "Int32" )

Asociácie Asociácie medzi objektami ktoré predstavujú vzťahy medzi tabuľkami je možné namodelovať oba smery a všetky tri násobnosti. Násobnosť v XML mapovaní je vyjadrená uzlom s charakteristickým názvom: one-to-one , one-to-many a many-to-many . V základe sú asociácie jednosmerné, typicky obojsmerné asociácie bývajú násobnosti 1:M a M:N. Pri zmene v databáze je nutné upraviť mapovania a modely obchodnej logiky ručne, resp. prostredníctvom pôvodne použitého nástroja. Pre mapovanie dedičnosti sú podporované všetky tri základné návrhové vzory (viď podsekcia 4.2.1): • Dedičnosť jednej tabuľky • Dedičnosť konkrétnej tabuľky • Dedičnosť tabuľky triedy Okrem nich NHibernate podporuje aj štvrtý typ, implicitný polymorfizmus ( Implicit polymorphism ).

Objekty Vytvorený objekt (charakterizujúci riadok tabuľky), ktorého inštancia nie je spojená s konkrétnou Session je prechodného typu ( Transient ). To, že neexistuje asociácia so Session znamená, že sa nenachádza v jej Mape identity (viď podsekcia 4.3.3), teda existuje len v pamäti a nebol ešte uložený do databázy, resp. z nej bol zmazaný. Zmeny v dátach tohoto objektu nie sú sledované. Protikladom sú objekty udržujúce dáta z databázy, vytvorené v rámci Session, po ktorej zatvorení je možné použiť tieto objekty v inej vrstve aplikácie. Toto sú objekty trvalé ( Permanent ). Okrem načítaných dát z databázy sem patria aj vytvorené objekty, ktoré sú do databázy uložené. Sú vždy charakterizované primárnym kľúčom. Poslednou skupinou sú objekty oddelené, odpojené ( Detached ), ktoré sú uložené v databáze, ale nie sú aktuálne spojené so žiadnou Session , takže zmena stavu sa trvalo nezapisuje. Hlavným rozdielom od trvalých objektov je neexistujúca garancia ekvivalencie medzi dátami objektu v pamäti a dátami v databáze. Pre riadenie stavov objektov sa dajú použiť metódy Evict() (objekt je odstránený z medzipamäte prvej úrovne a je zabránené jeho synchronizácii do databázy), Merge() (odpojený a prechodný objekt sa zmení na trvalý) a Persist() (prechodný objekt je pripojený k Session ).

73 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE Pokročilé vlastnosti Stratégia riadenia súbežnosti sa odvíja od niekoľkých nastavení, hlavný vplyv na stratégiu má hodnota levelu izolácie ( Isolation Level ). Jednotlivé možnosti sú zoradené od najpomalšieho spôsobu po najrýchlejší: • Serializable : Zmeny v dátach sú serializovateľné. • Snapshot : Vytváranie snímkov používaných dát. • RepeatableRead : Všetky dáta používané v dopytoch sú zamykané. • ReadCommited : Pri čítaní sú použité zdieľané zámky. • ReadUncommited : Neexistujú žiadne zdieľané ani exkluzívne zámky, je možné špinavé načítavanie (načítavanie už neaktuálnych hodnôt). Základné nastavenie izolácie v NHibernate je ReadCommited. NHibernate má prepracovanú podporu medzipamäte dát umožňujúcu zvýšenie výkonu pri opakovanom čítaní. Toto zvýšenie výkonu je dosiahnuté redukciou počtu databázových operácií, resp. ich úplným odstránením. Medzipamäť môže byť prvej, alebo druhej úrovne. Prvá úroveň medzipamäte je automaticky aktivovaná a jej životnosť je v rámci aktuálnej Session . Je implementovaná pomocou už spomínanej Mapy identít. Voliteľným nastavením NHibernate je medzipamäť druhej úrovne, ktorej životnosť je v rámci SessionFactory . Existuje množstvo doplnkov pre NHibernate, ktoré dokážu pracovať ako medzipamäť druhej úrovne, napr. Prevalence, MemCached, SysCache alebo AppFabric (známe ako Velocity).

7.3.6 Použitie Na dopytovanie relačnej databázy a získavanie dát prostredníctvom NHibernate existuje viacero možností. Vždy je potrebný objekt Session . Nasledujú rôzne spôsoby, s ktorými je možné načítavať dáta z databázy, ukážkové zdrojové kódy umožňujú načítať všetky riadky z tabuľky Shippers: • HQL IQuery : HQL (Hibernate Query Language ) je dopytovací jazyk veľmi podobný SQL, rozšírený o spôsob pristupovania k objektovým štruktúram. V zdrojovom kóde je reprezentovaný textovým reťazcom. // HQL IQuery IList query1 = session.CreateQuery( "from Shipper" ) .List< Shipper >(); HQL je jazyk určený len k získavaniu dát a nie na manipuláciu s nimi, dáta sú v základnom nastavení získavané lenivo (vzor Lazy Loading). Funkcionalita HQL je zrovnateľná s SQL, podporuje bežné agregačné funkcie, spájanie tabuliek, radenie výsledkov, vyhľadávanie vo vnútri reťazcov pomocou LIKE, stránkovanie výsledkov, volanie databázových procedúr, vykonávanie zanorených dopytov. Názvy parametrov dopytu je možné označiť (dvojbodkou) a neskôr pridať ich skutočné hodnoty, čo je výhodné, ak sa niektorý parameter opakuje viackrát. Druhý spôsob (pozičné parametre) znamená namiesto parametru použiť otáznik a hodnoty parametrov do dopytu vložiť v správnom poradí. 74 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE HQL dokáže z databázy získavať len predom určené vlastnosti entít, z hľadiska výkonu je to výhodnejšie ako načítavať celú entitu. Ďalšie zvýšenie výkonnosti sa dá dosiahnuť pomocou používania MultiQuery , keď dva a viac dopytov do databázy je vykonaných naraz. Dopyt DetachedQuery je možné vytvoriť aj bez asociácie so Session , ku ktorej je „pripojený“ až neskôr. • ICriteria : Dopyty sú zostavované algoritmicky, pomocou skladania rôznych metód (kritérií). // ICriteria IList query2 = session.CreateCriteria( typeof (Shipper )) .List< Shipper >(); ICriteria nenačítava dáta lenivo v štandardnom nastavení, čo je rozdiel oproti HQL. Spôsoby načítavania dát ( FetchMode ), ktoré platia aj pre HQL a môžu byť špecifikované v mapovaní sú nasledovné: o Okamžité ( Immediate ) načítavanie: Objekt spolu s pridruženými objektami je načítaný okamžite. Tento spôsob je výhodný, ak sú očakávané pridružené objekty umiestnené v medzipamäti. o Lenivé ( Lazy ) načítavanie: Pridružené objekty sú z databázy načítané až v prípade potreby. o Netrpezlivé ( Eager ) načítavanie: Je možné explicitne označiť ktoré pridružené objekty sa načítajú okamžite s hlavným objektom. Pri databázovom dopyte sa využíva vonkajšie spojenie (outer join). o Hromadné ( Batch ) načítavanie: Je to určitá forma optimalizácie lenivého, alebo netrpezlivého načítavania. ICriteria podporuje transformácie pomocou objektov Transformers, slúžia na konverziu akýchkoľvek výsledkov na DTO ( Data Transfer Object ), objekty určené k posielaniu dát medzi rôznymi subsytémami v aplikácii. Nevýhodou ICriteria je horšia čitateľnosť oproti HQL. Motiváciou pre rozšírenie ICriteria spôsobom nazvaným QueryOver je zaobalenie API ICriteria do typovo bezpečnej formy kontrolovanej kompilátorom. Toto zaobalenie eliminuje závislosť ICriteria na používaných textových reťazcoch, ktoré môžu spôsobiť pád aplikácie za behu. Dopytovanie pomocou QueryOver využíva lambda výrazy. // QueryOver IList query3 = session.QueryOver< Shipper >() .List(); • LINQ to NHibernate: Od verzie 3 je k dispozícii poskytovateľ pre dopytovanie pomocou LINQ, ktorý podporuje väčšinu operácií. // LINQ IQueryable query4 = from s in session.Query< Shipper >() select s; V NHibernate však nepredstavuje ideálnu formu dopytovania, napr. v porovnaní funkčnosti s Entity Frameworkom. 75 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE • Native SQL: Umožňuje získavanie dát pomocou klasického SQL dopytu. // Native SQL ISQLQuery query5 = session.CreateSQLQuery ("SELECT * FROM Shippers" ) .AddEntity( typeof (Shipper )); Ďalším spôsobom dopytovania je Query by Example, kde ako parameter stačí poskytnúť entitu s niekoľkými priradenými vlastnosťami a NHibernate nájde všetky entity v databáze, ktoré sa na vzorovú entity podobajú.

Doplnky pre NHibernate Pre NHibernate existuje množstvo rozšírení a doplnkov. Už bol spomenutý Fluent NHibernate ponúkajúci alternatívnu formu zápisu mapovania. Medzi ďalšie populárne doplnky patria napr.: • Castle ActiveRecord: Nástroj postavený nad NHibernate, ktorý v mnohých ohľadoch zjednodušuje prácu a implementuje návrhový vzor Aktívny záznam. • Visual NHibernate: Komerčná aplikácia určená na vytvárania modelu entít. • Burrow: Jednoduchá vrstva určené pre bezstavové webové aplikácie, určená na správu Session a transakcií. • NHibernate ProxyGenerators: Doplnok určený na predgenerovanie Lenivého nahrávania. • NHibernate.Spatial: Rozšírenie NHibernate uľahčujúce prácu s geolokačnými dátami. [53], [54], [55]

76 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE 7.4 LLBLGen Pro

Výrobca Solutions Design nazýva produkt LLBLGen Pro ako riešenie pre prístup k dátam, ktorý pozostáva z dvoch častí: LLBL Gen Pro Designer (ďalej len Designer) a LLBLGen Pro Runtime Framework . Aplikácia Designer slúži na tvorbu doménového modelu entít, tvorbu mapovania a generovanie zdrojového kódu pre rôzne ORM nástroje, medzi ktoré patrí aj Runtime framework. Vygenerovaný kód je pre každý jeden nástroj špecifický a nezameniteľný.

7.4.1 História LLBLGen Pro je nasledovníkom open-source generátoru kódu LLBLGen z roku 2002, ktorý prebrala holandská firma Solutions Design a ďalej ho vyvíja ako komerčný produkt. Prvá verzia pochádza z roku 2003. Aktuálna nová verzia 4.0 z apríla 2013 nahrádza verziu 3.5 z marca 2012.

7.4.2 Cena LLBLGen Pro je možné získať v jednej z troch verzií: • Lite: Táto verzia je zdarma, ale s obmedzením na maximálne osem entít. • Standard: Cena za licenciu pre jedného užívateľa je 299 € bez dph (9300 Kč s dph), pri nákupe 21 licencií a viac sa cena za jednu pohybuje od 239 € bez dph (7400 Kč s dph). Pri nákupe väčšieho počtu licencií je možná dohoda individuálnych cien. • Plus: Oproti verzii Standard je cena vyššia o 99 €, ktorú zákazník platí za nástroj ORM Profiler. Účelom tohoto nástroju je monitorovanie pomalých dopytov a hľadanie neefektívneho využitia databáze. K dispozícii zdarma je aj 30-dňová skúšobná verzia bez obmedzení na počet entít, ktorá bola použitá v praktickej časti tejto práce (sekcia 8.1). U oboch platených verzií Solutions Design garantuje aktualizácie stávajúcej verzie zdarma, nová verzia LLBLGen je stávajúcemu zákazníkovi k dispozícii za nižšiu cenu. V cene produktu je započítaná aj podpora.

7.4.3 Dokumentácia Veľmi obsiahla dokumentácia pre každú z verzií 2.6 a vyššie je dostupná on-line na adrese http://www.llblgen.com/documentation. Priamo z aplikácie Designer sú prístupné rôzne scenáre popisujúce typické použitie: Generovanie zdrojových kódov podľa databáze, zmena vygenerovaného kódu a následná zmena v databáze, a pod. Literatúra pre tento nástroj prakticky neexistuje, jediná kniha je z roku 2006 a prácu s LLBLGen Pro popisuje len čiastočne. Z webu výrobcu je prístupné aj fórum s približne stotisíc príspevkami, ktoré je priamo zamerané na produkt a riešenie rôznych problémov s ním spojenými.

77 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE Po inštalácii produktu je pevnom disku k dispozícii niekoľko stoviek praktických príkladov a ukážkových dopytov pre LINQ to LLBLGen Pro, Native API a QuerySpec. Výrobca na svojich stránkach poskytuje zoznam zákazníkov používajúcich LLBLGen Pro. Ide o veľké firmy, medzi najznámejšie patria Dell, IBM, 3M, Intel, Motorola, Siemens, Oracle, Microsoft, Ubisoft, či Verizon. [56]

7.4.4 Podporované databázy LLBLGen podporuje generovanie kódu pre široké spektrum databáz za využitia rôznych verzií dátových poskytovateľov ADO.NET spomínaných v podsekcii 5.1.1. • SQL Server 2000-2012 vrátane verzií Express a Compact, poskytovateľ SqlClient. • Microsoft Access 2000-2013 za použitia poskytovateľa OLE DB. • Oracle 9-11 s poskytovateľmi ODP.NET a OracleClient 37 . • PostgreSQL 7.4 a vyššia s poskytovateľom Npgsql. • Firebird 1.x/2.x s poskytovateľom Firebird.NET. • IBM DB2 verzia 7 a vyššia s IBM DB2 .NET poskytovateľom. • MySql verzie 4 a 5 s poskytovateľom MySQLDirect. • Sybase iAnywhere a Adaptive Server Enterprise s poskytovateľmi ASA a ASE. Minimálna verzia .NET pre spustenie LLBLGen Pro aplikácie je 3.5 a je možné generovať zdrojové kódy pre .NET 3.5, 4.0 a 4.5, podporované jazyky sú C# a Visual Basic.

7.4.5 Architektúra a mapovanie

Komponenty LLBLGen Pro Základná terminológia používaná autormi LLBGen Pro je nasledovná: • Prvky kódu ( Code Elements ) sú zdrojové kódy tried. • Prvky databázovej schémy ( Database Schema Elements ) sú samotné databázové tabuľky, resp. pohľady na dáta. • Abstraktná definícia entity ( Abstract Entity Definition ) je súčasťou abstraktného modelu entít a obsahuje prvky kódu a databázovej schémy. Je premietnutá do spustiteľnej formy, do zdrojového kódu triedy v C# a do SQL skriptu pre vytvorenie databáze. • Abstraktný model entít ( Abstract Entity Model ) je celkový model a pozostáva s abstraktných definícii entít. • Mapovanie ( Mapping ) predstavuje definíciu, ktorá spája jeden prvok kódu (triedu) s jedným prvkom databázovej schémy (s tabuľkou).

37 Od verzie .NET 4.0 nie je doporučené používať poskytovateľa OracleClient z menného priestoru System.Data 78 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE • Inštancia definície entity ( Entity Definition Instance ) predstavuje dáta. Je to inštancia abstraktnej definície entity, čiže predstavuje inštanciu prvku kódu (vytvorený objekt), ktorá je ekvivalentná s inštanciou databázovej schémy (riadok tabuľky). • Projekcia (Projection ) existuje v dvoch rôznych formách (obrázok 7.2): 1. Projekcia z abstraktného modelu entít na prvok databázovej schémy: Toto premietnutie je vytvorené aplikáciou Designer podľa mapovania medzi definíciou entity a tabuľkou. 2. Projekcia z abstraktného modelu entít na prvok kódu: Vzniká pri generovaní kódu, keď je z definície entity vytvorená jedna alebo viacej tried typu partial, takže v iných častiach zdrojového kódu môžu byť rozšírené o ďalšiu funkcionalitu.

Obrázok 7.2: Projekcie [57] • Cieľový framework ( Target Framework ) je ORM nástroj, prostriedok určený k manipulácii s dátami.

Tvorba modelu Designer bol do verzie 3.5 dostupný ako externá aplikácia, od poslednej verzie 4.0 je možné ho spúšťať ako šablónu v rámci vývojového prostredia Visual Studio 2010 a 2012. Pomocou neho sú vytvárané definície entít, ktoré pre svoju činnosť potrebuje samotný ORM nástroj, ktorý je v rámci aplikácie Designer nazývaný ako Target Framework. LLBLGen Pro Designer podporuje cieľových frameworkov niekoľko. Je možné generovať mapovanie pre všetky verzie konkurenčného Entity Frameworku (v1, v4 a v5), LINQ to SQL a NHibernate (v2 a v3), pre ktorý je na výber generovanie XML alebo FluentNHibernate mapovania. Výhodou je generovanie mapovania pre posledné menovaný nástroj, ktorý žiadnym automatizovaným spôsobom mapovania nedisponuje. Okrem ORM tretích strán je samozrejme možné použiť aj LLBGen Pro Runtime Framework. Designer ponúka dva rôzne spôsoby tvorby abstraktného modelu entít: • Model entít je vytvorený podľa existujúcej databázy ( Database First ): Designer podľa tabuliek a ich cudzích kľúčov, pohľadov a databázových procedúr vytvorí

79 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE reverzným inžinierstvom abstraktný model entít a mapovanie, z ktorých sú následne vygenerované prvky kódu, viď obrázok 7.3. Zjednodušený proces tvorby takéhoto modelu je nasledovný: 1. Po vytvorení projektu a pripojení sa k existujúcej databáze je nutné si zvoliť tabuľky, pohľady a databázové procedúry, ktoré majú byť v modeli zahrnuté. 2. Po vytvorení modelu sa dá reverzným inžinierstvom vytvoriť definície entít. 3. Posledným krokom je generovanie zdrojového kódu, kde prichádza na rad voľba verzie .NET, programovacieho jazyku, spôsob práce s dátami a jeho variant (paradigma, vysvetlené neskôr) a cieľovú zložku. V tomto kroku je rovnako možné pomocou šablón ( templates ) prispôsobiť vygenerovaný kód ďalším požiadavkám, napríklad pridanie vlastnej biznis logiky. V prípade už existujúceho projektu môže nastať situácia, keď príde k zmene v databáze. V tomto prípade je nutné otvoriť v projekt v aplikácii Designer, zvoliť obnovu modelu z databáze a pokračovať podľa kroku číslo tri z predchádzajúceho postupu.

Obrázok 7.3: Model podľa databázy [57] • Model entít je vytvorený prvý a schéma databázy je vygenerovaná následne ( Model First ): Model entít a mapovanie sú vytvorené ručne v prostredí aplikácie, podľa ktorých sú vygenerované prvky kódu a prvky databázovej schémy, viď obrázok 7.4. Opäť nasleduje zjednodušený postup: 1. Po vytvorení modelu je nutné ručne pridať jednotlivé entity a ich vzťahy. 2. Pri voľbe dedičnosti je na výber jeden z dvoch návrhových vzorov na jej mapovanie (oba sú spomínané v podsekcii 4.3.4): a) Dedičnosť jednej tabuľky ( Single table inheritance ), ktorý je nazvaný TargetPerEntityHierarchy. b) Dedičnosť tabuľky triedy ( Class table inheritance ), ktorý je nazvaný TargetPerEntity. 3. Nasleduje voľba databázy. 4. Z entít je nutné vygenerovať mapovanie na nové databázové tabuľky. 5. Nasleduje vytvorenie DDL SQL skriptu, ktorý tvorí schému novej databáze. 6. Posledným krokom je opäť generovanie zdrojového kódu.

80 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE

Obrázok 7.4: Databáza podľa modelu [57]

Paradigmá pre prácu s dátami LLBLGen Pro rozlišuje dva rôzne spôsoby práce s dátami (paradigmá), z ktorých si je nutné vybrať pred vygenerovaním zdrojového kódu: • SelfServicing : Vygenerované entity sú samostatné, obsahujú vlastné metódy zabezpečujúce prácu s databázou, teda ukladanie a čítanie dát, na ktoré nie je potrebný žiadny iný objekt. Toto paradigma je podobné návrhovému vzoru Aktívny záznam (podsekcia 4.3.2) a je možné ho zvoliť len v prípade použitia jednej databáze. SelfServicing je možné vygenerovať v dvoch variantoch: o General: Pre každú entitu je vygenerovaná práve jedna trieda. o TwoClasses: Pre každú entitu sú vygenerované dve triedy. Prvá má v názve „EntityBase“ a obsahuje komunikáciu s databázou, druhá od nej dedí a obsahuje samotnú biznis logiku. • Adapter : Entity obsahujú informácie len o sebe, o komunikáciu s databázou sa stará vlastná vrstva – objekt Adaptér. Toto paradigma je podobné návrhovému vzoru Dátový mapovač (podsekcia 4.3.2) a je možné ho zvoliť v prípade použitia dvoch a viacerých rozdielnych databáz, keď jeden objekt komunikuje s rôznymi databázami prostredníctvom rozličných adaptérov. Adapter existuje opäť v dvoch variantoch General a TwoClasses s rovnakým významom ako paradigma SelfServicing.

7.4.6 Použitie Pri dopytovaní dát z databázy prostredníctvom LLBLGen Pro Runtime frameworku sú podporované dva rôzne spôsoby: • QuerySpec : Je API postavené nad základným a natívnym Query API. Podporuje fluent syntax písania dopytov a štruktúrou je podobné SQL. Ukážka načítania všetkých zákazníkov podľa krajiny:

81 KAPITOLA 7: VYBRANÉ ORM NÁSTROJE var qf = new QueryFactory (); var q = qf.Customer.Where(CustomerFields.Country == "Germany" ); var customers = new CustomerCollection(); customers.GetMulti(q); • LINQ to LLBLGen Pro: Runtime framework podporuje plnú LINQ syntax, každý jeden dopyt vytvorený pomocou QuerySpec je možné zapísať v LINQ, ide teda o plnohodnotnú alternatívu. Predchádzajúci dopyt zapísaný pomocou LINQ: LinqMetaData metaData = new LinqMetaData (); var q = from c in metaData.Customer where c.Country.Equals("Germany" ) select c; List customers = q.ToList(); Oba spôsoby je možné používať naraz v rámci jedného projektu, lebo sú transformované do natívneho Query API, ktoré pozostáva s predikátov, vzťahov a metód na načítavanie objektov. V rámci LINQ dopytu je možné špecifikovať príbuzné entity, ktoré sa načítajú v rámci prevedenia databázovej operácie. Táto funkcionalita sa volá Prefetch Path .

Pokročilé vlastnosti LLBLGen Pro Runtime framework ponúka množstvo špecifických vlastností, medzi najvýznamnejšie patria: • Vlastný IoC/DI 38 mechanizmus pre manipuláciu s objektami určenými pre validáciu, čí autorizáciu entít. • Nepodporuje POCO entity, každá vygenerovaná entita dedí od spoločnej triedy CommonEntityBase . • Vďaka typovým konverziám (objekty TypeConverters ) je možné vytvoriť mapovania akéhokoľvek dátového typu objektu na akýkoľvek dátový typ v tabuľke. • Podpora vlastnej medzipamäte na výsledky databázových dopytov, ktoré je možné v pamäti uchovať po predom určený čas. • Podpora návrhového vzoru Pracovná jednotka, ktorý dokáže zjednotiť niekoľko databázových operácií do jednej transakcie. • Podpora návrhového vzoru Mapa identity pomocou objektov kontextu ( Context Objects ). Tento návrhový vzor zabezpečuje niekoľkonásobné načítanie entity do jednej inštancie. • Podpora Lenivého nahrávania, teda nahrania dát až v prípade potreby. • Je možné použiť viacero databáz v jednom projekte, vtedy je nutné použiť paradigma Adapter a nie SelfService. • Možnosť validácie prostredníctvom validačných objektov ( Validator objects ) vytvorených pomocou rozšírení základnej triedy.

38 IoC/DI (Inversion of Control / Dependency Injection) predstavujú pojmy keď kód aplikácie nie je závislý na jednotlivých triedach, ale na rozhraniach. Referencie na triedy sú spravované kontajnerom DI. 82 Kapitola 8 Testovanie

ORM nástroje z kapitoly 7 boli použité a z hľadiska výkonu otestované v aplikácii ORM Test, ktorú popisuje nasledujúca kapitola. Všetky testy boli vykonané aj pomocou ADO.NET. Na záver bol spôsob práce a výkon porovnaný s NoSQL databázou RavenDB. 8.1 Testovacia aplikácia

Aplikácia určená na testovanie výkonnosti ORM nástrojov sa volá ORM Test a je napísaná v jazyku C# pomocou vývojového prostredia Visual Studio 2012, pre verziu 4.5 platformy .NET. ORM Test má grafické rozhranie vytvorené pomocou technológie WPF (obrázok 8.1) a využíva návrhový vzor MVVM (Model, View, ViewModel), teda grafická vrstva je nezávislá a v maximálnej miere využíva prepojenie dát z nižšej vrstvy ViewModel. Kompletné riešenie ( Solution ) obsahuje ďalšie projekty, ide o mapovania a entitné modely jednotlivých ORM nástrojov a databázy RavenDB. Ďalej boli vytvorené dve jednoduché konzolové aplikácie: Prvá (RavenHandler) slúži na tvorbu indexov pre databázu RavenDB a ponúka pomocné funkcie na transformáciu dát relačnej databázy do dokumentov „plochého“ formátu JSON pre spomínanú databázu RavenDB. Druhá konzolová aplikácia (ProteinLite) porovnáva zápis náhodne vygenerovaných záznamov do súborov a do databáz SQL Server a RavenDB. Jedná sa o desiatky až tisíce objektov v celkovej veľkosti až 10 GB.

Obrázok 8.1: Aplikácia ORM Test 83 KAPITOLA 8: TESTOVANIE 8.2 Prostredie

Všetky testy boli uskutočnené na bežnom kancelárskom počítači s procesorom Intel Pentium G2020 (2.9 GHz) a 8 GB operačnej pamäte. 64-bitový systém Windows 8 bol nainštalovaný na SSD disku, rovnako ako oba databázové servery. Pri testovaní zápisu aplikáciou ProteinLite boli testovacie dáta ukladané na bežný 7200 otáčkový disk (HDD) z dôvodu veľkého opotrebenia SSD pri opakovanom zapisovaní veľkého množstva dát. Databáza SQL Server bola vo verzii 2012 Enterprise (64-bit), RavenDB build bol verzie 2330. Relačná databáza s názvom NorthPV predstavuje kombináciu ukážkovej databázy Northwind a časti skutočnej databázy využívanej systémom riadiacim výrobu solárnych panelov (PV = Photovoltaics). Diagramy databáze sú na obrázkoch v prílohe A. Tabuľky z časti databáze v reálnom systéme obsahujú viac ako 120 stĺpcov, z dôvodu miesta je v prílohe len časť diagramu, celý diagram je uložený v elektronickej prílohe. Veľkosti databázových tabuliek (pred vkladaním testovacích záznamov) sú zobrazené v tabuľke 8.1. Databázová tabuľka Glasses obsahuje zoznam skiel solárnych panelov, každý z nich sa skladá zo šiestich stringov uložených v tabuľke Stringers, každý string obsahuje desať cellov 39 (tabuľka Cells). Pohľad na dokumenty databáze RavenDB je na obrázku 8.2. Suppiers Products OrderDetails Orders Customers Shippers Glasses Stringers Cells 29 77 2155 830 91 3 3146 18114 173914 Tabuľka 8.1: Počty riadkov v tabuľkách relačnej databáze NorthPV

Obrázok 8.2: Počty dokumentov v NoSQL databáze NorthPV

39 Cell je kremíková bunka, solárny panel je tvorený zo 60 kusov. Toto množstvo sa môže líšiť podľa výrobcu. 84 KAPITOLA 8: TESTOVANIE 8.3 Testy

8.3.1 Testy aplikácie ORM Test Testovacia aplikácia obsahuje 20 testov, v ktorých boli jednotlivé ORM nástroje porovnané spolu s ADO.NET a RavenDB.

Prehľad nástrojov • ADO.NET: Tento komponent predstavuje najrýchlejší spôsob dopytovania a manipulácie s dátami v relačnej databáze pomocou SQL. Do testovania bol zahrnutý z dôvodu zistenia pridaných réžijných nákladov pri použití niektorého z nasledujúcich ORM nástrojov. • Entity Framework: Je použitá aktuálna verzia 5.0 a všetky testy sú zapísané pomocou LINQ. • LINQ to SQL: Testy sú zapísané pomocou LINQ, jedna séria testov obsahuje LINQ výrazy skompilované. Do testovania bol tento ORM nástroj zahrnutý z dôvodu porovnania výkonnosti s Entity Frameworkom a z dôvodu porovnania rýchlosti nekompilovaných a kompilovaných LINQ výrazov. • LLBLGen Pro: Jediný zástupca komerčných ORM nástrojov v testovacej aplikácii. V čase písania tejto práce bola vydaná nová verzia 4.0, v testoch sa teda vyskytuje spolu s jej predchodcom, verziou 3.5. Testy sú zapísané pomocou LINQ. • NHibernate: Jeden z najvyspelejších ORM na trhu bol otestovaný v poslednej verzii 3.3.3. Všetky testy sú zapísané pomocou HQL a v prípade možnosti je využitý aj poskytovateľ LINQ to NHibernate. • RavenDB: Pre všetky testy, ktoré boli vykonané na relačnej databáze SQL Server boli vytvorené patričné indexy a LINQ testovacie výrazy. RavenDB bol zvolený ako zástupca NoSQL databáz s cieľom porovnať prácu na platforme .NET s použitím ORM a relačnej databázy. Zároveň je k dispozícii zrovnanie rýchlosti oboch databázových serverov.

Prehľad testov Nasleduje zoznam testov spolu s ich krátkym popisom, názvy sú zvolené tak ako sa vyskytujú v programe. Zdrojové SQL, LINQ a HQL kódy sú v prílohe B. • SelectPV1: Načítavanie dvoch stĺpcov (GlassID a WoID) z tabuľky Glasses pre panely s výkonom 260 W, spolu 498 riadkov. • SelectPV2: Zhodný test ako prechádzajúci s rozdielom použitia databázovej procedúry. • SelectPV3: Načítanie unikátnych hodnôt GlassID s využitím spojenia tabuliek Glasses a Stringers s podmienkou špecifického PartNo (9B.M2P09.102) a najmenšieho dátumu vytvorenia stringerov (4. 3. 2013), spolu 358 riadkov.

85 KAPITOLA 8: TESTOVANIE • SelectPV4: Zhodný test ako predchádzajúci s rozdielom načítavania jedenásť stĺpcov namiesto jedného. • SelectPV5: Využitie spojenia troch tabuliek Glasses, Stringers a Cells a načítanie všetkých skutočných hodnôt výkonov panelov spolu s priemerom účinnosti 40 príslušných šesťdesiat cellov, spolu 2939 riadkov. • SelectNW1: Načítanie desať najdrahších produktov z tabuľky Products. • SelectNW2: Zhodný test s predchádzajúcim, je použitá bezparametrová databázová Northwind procedúra Ten Most Expensive Products. • SelectNW3: Spojenie až štyroch tabuliek Customers, Orders, Order Details a Products a načítanie mien jednotlivých zákazníkov spolu so súčtom jednotlivých nimi objednaných produktov, spolu 1685 riadkov. • SelectNW4: Načítanie jedného riadku z tabuľky Suppliers. • InsertNW1: Vloženie jedného riadku do tabuľky Shippers. • InsertNW2: Vloženie desiatich riadkov do tabuľky Suppliers. • InsertNW3: Vloženie desiatich riadkov podobne ako v prechádzajúcom teste s rozdielom vkladania v potvrdenej transakcii. • InsertNW4: Vloženie desiatich riadkov podobne ako v teste InsertNW2 s rozdielom vkladania v zrušenej transakcii. • UpdatePV1: Zmena jednej hodnoty v riadku v tabuľke Customers. • UpdatePV2: Zmena 91 riadkov v tabuľke Customers, zmenený jeden stĺpec (City). • DataContext1: Vytvorenie potrebných objektov k práci s databázou (SqlConnection , SqlCommand u ADO.NET, kontexty a session u ORM nástrojov a RavenDB). • Threads1: V jednom vytvorenom vlákne vloženie jedného záznamu do tabuľky Shippers. • Threads5: V piatich vytvorených vláknach naraz vkladanie jedného záznamu do tabuľky Shippers. • Threads10: V desiatich vytvorených vláknach naraz vkladanie jedného záznamu do tabuľky Shippers. • Threads15: V pätnástich vytvorených vláknach naraz vkladanie jedného záznamu do tabuľky Shippers. • Library cold load: Test, ktorý bol vykonaný nasledovne: Po štarte aplikácie bol spustený test SelectPV1 v sto opakovaniach, od prvého najdlhšieho času bol odrátaný priemer všetkých časov a tak bol vyrátaný čas na inicializáciu potrebného ORM nástroja.

40 Dnes používané kremíkové celly pracujú s učinnosťou premeny slnečnej energie na elektrickú asi 20%. 86 KAPITOLA 8: TESTOVANIE Metodika testovania Zjednodušený kód testovania vyzerá nasledovne: CleanGC(); WarmUP(); TotalTime.Start() for(int i = 0; i < OuterRepeat; i++) { SingleTime.Start(); TestInvoke(); SingleTime.Stop(); SingleTimes.Add(SingleTime); } TotalTime.Stop(); Podľa počiatočných nastavení je vyčistený Garbage Collector. Nasleduje voliteľné „zahriatie“ pomocou metódy WarmUp() , ktorá testovaciu metódu spustí 20-krát. Na samotné meranie testov je v aplikácii výber jedna z troch možností: • Batch: Odmeranie celkového času TotalTime , je k dispozícii priemerná hodnota (Average ) ako podiel celkového času a počtu opakovaní OuterRepeat . • Single: Merania jednotlivých iterácii SingleTime sú uložené v zozname SingleTimes . Aplikácia ORM Test vo výsledkoch testovania zobrazuje informáciu o najkratšom a najdlhšom čase, priemerný čas zo všetkých SingleTimes (Mean ), počet operácií za jednu sekundu, medián hodnôt, štandardnú odchýlku merania a zoznam jednotlivých časov. • Batch + single: Meranie predstavuje zjednotenie oboch predchádzajúcich možností. Je odmeraný celkový čas TotalTime a všetky časy iterácii SingleTime . Vo výsledkoch merania sú k dispozícii hodnoty spomínané v možnostiach Batch a Single, na obrázku 8.3 sú tieto výsledky pre test SelectPV1 a nástroj LLBLGen Pro 3.5 pri počte 300 opakovaní.

Obrázok 8.3: Ukážka výsledkov merania 87 KAPITOLA 8: TESTOVANIE Niektoré testy (napríklad vytváranie kontextu DataContext1) sú vykonané aj pri počte 300 iterácií veľmi rýchlo, výsledný čas sa pohybuje menej ako 1 ms. Aplikácia preto podporuje iteráciu v rámci testovacej metódy ( TestInvoke() ) podľa veľkosti hodnoty InnerRepeat : TestInvoke() { for(int i = 0; i < InnerRepeat; i++) { DatabaseOperation(); } } Vo výsledku je teda možné lepšie porovnanie rýchlych testov medzi jednotlivými nástrojmi. Všetky namerané výsledky sú v tabuľkách v prílohe D, každý test bol zopakovaný v 300 iteráciách. Pre niektoré testy bol nastavený parameter InnerRepeat na väčšiu hodnotu ako jedna, vyjadruje to príslušný názov, napr. SelectNW1 x10. Pre skutočné meranie jednotlivých časov každej z testovacích iterácií bol využitý komponent .NET-u System.Diagnostics.Stopwatch .

Výsledky testov Jednotlivé testy sú v rozdelené v grafoch podľa časov a zamerania z dôvodu lepšej čitateľnosti a hlavne možnosti lepšieho porovnania rôznych nástrojov. Graf 8.1 zobrazuje porovnanie výkonnosti prvých štyroch testov. Test SelectPV2 je načítavanie pomocou databázovej procedúry, niektoré ORM a RavenDB touto funkcionalitou nedisponujú. Načítavanie pomocou ADO.NET je najrýchlejšie. Z ORM nástrojov je najrýchlejšie dopytovanie pomocou kompilovaného LINQ to SQL a NHibernate HQL. RavenDB pre porovnanie podáva najhoršie výsledky, jednotlivé časy testov sú pomerne vyrovnané a nie sú závislé od počtu načítavaných stĺpcov (resp. v tomto prípade od počtu častí dokumentu). 25

20

15

10 čas čas (ms)

5

0

SelectPV1 SelectPV2 SelectPV3 SelectPV4

Graf 8.1: Výsledky testov načítavania 88 KAPITOLA 8: TESTOVANIE Graf 8.2 zobrazuje druhú časť testov načítavania. Výsledky sú zhruba rovnaké ako v predchádzajúcom grafe 8.1, kompilované LINQ to SQL a NHibernate HQL sú po ADO.NET najrýchlejšie. Pre opakované načítavanie hodnôt v teste SelectNW1 boli prekvapujúco najpomalšie obe verzie LLBLGen Pro. RavenDB dosahuje opäť asi dvakrát až trikrát horšie výsledky ako ORM nástroje.

60

50

40

30

čas čas (ms) 20

10

0

SelectNW1 x10 SelectNW2 x10 SelectNW3 SelectNW4 x10

Graf 8.2: Výsledky testov načítavania Posledný test načítavania SelectPV5 je v grafe 8.3 zobrazený samostatne, vďaka pomerne veľkému časovému rozdielu od testov predchádzajúcich, ktorý by sa negatívne premietol do prehľadnosti hodnôt. Tento test predstavuje náročnú databázovú operáciu, takže do výsledkov sa viac premietla rýchlosť SQL Serveru ako rýchlosť jednotlivých ORM nástrojov. RavenDB je len dvakrát pomalší ako SQL Server. SelectPV5 250

200

150

100 čas čas (ms) 50

0

Graf 8.3: Výsledky testu načítavania

89 KAPITOLA 8: TESTOVANIE Pri manipulácii s dátami je po ADO.NET najrýchlejším ORM LLBLGen Pro. Najhoršie výsledky dosahuje prekvapivo Entity Framework. NHibernate HQL nedokáže vkladať dáta, tak sa v grafe tieto hodnoty pochopiteľne nenachádzajú. RavenDB je z grafu odstránený úplne, jeho časy sú násobne horšie ako EF, dokonca v poslednom teste UpdatePV2 dosahoval veľmi vysokého času, až 13 000 ms. 45 40 35 30 25 20 čas čas (ms) 15 10 5 0 ADO.NET EF 5.0 LINQ to LLBLGen LLBLGen NHibernate NHibernate SQL Pro 3.5 Pro 4.0 (HQL) (LINQ)

InsertNW1 x10 InsertNW2 InsertNW3 InsertNW4 UpdatePV1 x10 UpdatePV2 x10

Graf 8.4: Výsledky testov manipulácie s dátami Nasledujúce dva grafy porovnávajú výkonnosť vytvárania objektov potrebných na dopytovania a studený štart nástroja na začiatku aplikácie. LLBLGen Pro dosahuje výborných časov v oboch posledných verziách, na druhú stranu je vytváranie session v NHibernate o dosť pomalšie. Podľa grafu 8.5 dosahujú takmer všetky ORM čas štartovania knižníc takmer jednu sekundu, výnimkou je LINQ to SQL, ktorý je na štart veľmi rýchle, rozdiel oproti ADO.NET je len asi 50 ms. DataContext x50 3,5

3

2,5

2

1,5 čas čas (ms)

1

0,5

0 ADO.NET EF 5.0 LINQ to LLBLGen LLBLGen NHibernate RavenDB SQL Pro 3.5 Pro 4.0

Graf 8.5: Výsledok testu vytvárania kontextu

90 KAPITOLA 8: TESTOVANIE

Library cold load 1000 900 800 700 600 500 400 čas čas (ms) 300 200 100 0

Graf 8.6: Výsledok testu inicializácie nástrojov

Posledné porovnanie sa týka vkladania záznamov do databáz v niekoľkých vláknach súčasne, viď graf 8.7. Pre túto operáciu predstavujú LINQ to NHibernate a RavenDB dva najhoršie výsledky, pri ostatných ORM nástrojoch išlo o rozdiely podobné ako v grafe 8.4, teda ADO.NET opäť najrýchlejší, nasleduje LLBLGen Pro. EF a LINQ to SQL majú podobné, trochu horšie výsledky.

700

600

500

400

300 čas čas (ms)

200

100

0 ADO.NET EF 5.0 LINQ to LLBLGen LLBLGen NHibernate RavenDB SQL Pro 3.5 Pro 4.0 (LINQ)

Threads1 Threads5 Threads10 Threads15

Graf 8.7: Výsledky manipulácie s dátami vo vláknach

91 KAPITOLA 8: TESTOVANIE 8.3.2 Testy aplikácie ProteinLite Táto konzolová aplikácia predstavuje doplnkový test zápisu rozmerných dátových záznamov, ktoré približne odpovedajú štruktúram proteínu. Každý záznam sa okrem svojho názvu uloženého ako reťazec textu skladá z troch polí bajtov. Jednotlivé záznamy sú generované náhodne podľa nasledujúceho pravdepodobnostného rozloženia: • V 30 % ide o malý záznam veľkosti okolo 200 kB. • V 65 % ide o stredný záznam veľkosti okolo 500 kB. • V 5 % ide o veľký záznam veľkosti okolo 10 MB. Zápis prebiehal pre 10, 100, 500, 1000, 5000 a 10000 záznamov na tri rôzne miesta: • Na disk do súboru pomocou funkcie File.WriteAllBytes() . • Do relačnej databázy SQL Server 2012 tromi rôznymi spôsobmi: o Pomocou ADO.NET metódy SqlCommand.ExecuteNonQuery() a príkazu Insert() obsahujúcom dáta záznamu. Databáza do ktorej vkladanie prebiehalo mala pri prvom testovaní východzie nastavenie rozširovania svojho dátového súboru (MDF) o 1 MB. Pri druhom testovaní bolo toto rozširovanie zvýšené na 10 MB a ponechané pri ďalších nasledujúcich spôsoboch. o Pomocou ADO.NET objektu SqlBulkCopy umožňujúcom hromadné vkladanie dát do tabuliek. o Pomocou Entity Framework vkladania dát do kontextu s ukladaním každých sto záznamov. • Do NoSQL databázy RavenDB tromi rôznymi spôsobmi: o Ukladanie dokumentov obsahujúcich vygenerované dáta. o Znovu ukladanie dokumentov, ale pomocou objektu BulkInsertOperation . o Vkladanie dát do databázy vo forme príloh ( Attachments ). Každý test bol zopakovaný trikrát, vo výsledkoch v prílohe D je vždy uvedené množstvo prenesených dát, celkový čas a čas potrebný na zápis 1000 kB. Okrem zápisu bolo otestované aj načítavanie zo všetkých troch zdrojov (súbor, SQL Server a RavenDB).

Výsledky testov Pri ukladaní záznamov je očakávane najrýchlejší spôsob zápisu priamo do súboru. Priemerne je možné zapísať 1000 kB za menej ako 30 ms. Pomerne značný nárast predstavuje zápis do relačnej databázy s rozširovaním dátového súboru po 1 MB, 1000 kB zápis trvá priemerne 135 ms. Zvýšenie rozširovania na 10 MB predstavuje zníženie času na zápis okolo 85 ms. Použitie hromadného zápisu (bulk) pomocou ADO.NET a EF predstavuje ďalšie zrýchlenie asi o 5 ms. RavenDB vykázal priemerný čas zápisu 1000 kB do dokumentov približne 208 ms. Pri hromadných vkladaniach čas klesol na 158 ms, maximálne bolo možné zapísať najviac 1000 záznamov, pri väčších počtoch databáza odmietala pripojenie klienta. Najlepší výsledok 92 KAPITOLA 8: TESTOVANIE bol dosiahnutý pri ukladaní príloh, priemerný čas na zápis 1000 kB predstavuje 141 ms, čo je zrovnateľná hodnota s prvým výsledkom zápisu do relačnej databázy SQL Server. Vo výsledku je SQL Server pri zapisovaní dát takmer trikrát pomalší ako zápis do súboru, ale stále dvakrát rýchlejší ako RavenDB (viď grafy 8.8 a 8.9). Dáta boli zo všetkých troch miest načítavané, rozdiely medzi jednotlivými zdrojmi sú omnoho väčšie. Čítanie 1000 kB zo súboru zaberie asi 1 ms, SQL Server je pomalší päťkrát, RavenDB je od súboru pomalší až päťdesiatkrát (1 ms / 5 ms / 50 ms, graf 8.10). V nasledujúcich grafoch je zapisovanie a načítavanie dát porovnané podľa hodnoty času na zápis (načítanie) 1000 kB:

Zapisovanie (súbor a SQLServer) 180 160 140 120 100 80 60 40 20 Čas Čas zápisna 1000 kB (ms) 0

File.Write ADO.NET (1MB) ADO.NET (10MB) Bulk ADO.NET (10MB) Bulk EF (10MB)

Graf 8.8: Porovnanie zápisu č.1

93 KAPITOLA 8: TESTOVANIE

Zapisovanie (súbor a RavenDB) 250

200

150

100

50 Čas Čas zápisna 1000 kB (ms) 0

File.Write RavenDB dokumenty RavenDB bulk dokumenty RavenDB prílohy

Graf 8.9: Porovnanie zápisu č.2

Načítavanie 70

60

50

40

30

20 Čas Čas načítaniena 1000 kB (ms) 10

0 10 záznamov 10 záznamov 10 záznamov 100 záznamov 100 záznamov 100 záznamov

ADO.NET RavenDB prílohy File.Read

Graf 8.10: Porovnanie načítavania

94 KAPITOLA 8: TESTOVANIE 8.4 Vyhodnotenie

Vo všetkých uskutočnených testoch bol SQL Server znateľne rýchlejší ako RavenDB. Iný výsledok by zrejme nastal pri horizontálnom škálovaní, takéto testovanie by už bolo ďaleko nad rámec zamerania tejto práce.

Porovnanie ORM nástrojov Aplikácia bola pri dopytovaní s relačnou databázou podľa očakávaní najrýchlejšia za použitia ADO.NET. ORM nástroje prinášajú približne dvojnásobné spomalenie v testoch tak ako boli zostavené. Načítavanie je najrýchlejšie pomocou kompilovaného LINQ to SQL a pomocou NHibernate HQL. Celkovo najrýchlejší je nástroj LLBLGen Pro. Najlepšie sa vo Visual Studiu pracuje s Entity Frameworkom a na použitie a základnú funkcionalitu je najvhodnejší LINQ to SQL za predpokladu už funkčnej databázy. Z hľadiska jednoduchosti práce s ORM nástrojmi je dôležité na začiatku venovať čas návodom, ukážkam kódu a získať nejaké informácie o problematike. Potom je práca s ORM príjemná a rýchla. Dopytovanie dát pomocou SQL kódu by však stále malo patriť medzi základné schopnosti každého programátora. V prípade aplikácií spracovávajúcich dáta relačnej databázy v reálnom čase je použitie ADO.NET častokrát jedinou voľbou z dôvodu rýchlosti. Použitie ORM pri webových aplikáciách v rámci firmy, resp. na Internete prináša okrem mierneho zníženia výkonu pomerne značnú časovú úsporu pri vývoji a hlavne pri následnej správe aplikácie. Kód s ORM je prehľadnejší a čitateľnejší. Výhody a nevýhody ORM boli bližšie popísané v teoretických sekciách 4.4 a 4.5.

Použitie ORM Použitie ORM je najvýhodnejšie v aplikáciách s množstvom CRUD operácií. Vtedy je vývoj veľmi rýchly a programátor môže pohodlne zapisovať užívateľom poskytnuté dáta do databázy (objednávky, kontakty, plány). Pri statických reportoch, kde užívateľ zvolí niekoľko parametrov (dátum, tovar, výrobná linka) je lepšie použiť SQL dopyt a ten priamo zobraziť bez vytvárania objektov reprezentujúcich dáta (napr. HTML tabuľka v ASP webovej stránke). Záleží však od množstva iných okolností, ktoré majú vplyv na voľbu konkrétneho spôsobu manipulácie s databázou. Z hľadiska spôsobu práce s relačnou databázou za použitia ORM a s NoSQL databázou neexistuje veľa rozdielov. Pre laika by sa oba spôsoby práce mohli zdať totožné. Je nutné v zdrojovom kóde vytvoriť určitý prístupový objekt (kontext, session) a prostredníctvom neho načítavať objekty. Zmeny a ukladanie dát naspäť do databázy je opäť takmer rovnaké prostredníctvom špeciálnej metódy ( SaveContext() , SaveChanges() ). Práca s NoSQL databázou RavenDB prebiehala veľmi intuitívne a pohodlne.

Voľba databázy Zameranie a typ aplikácie by mali určovať typ databázy, ktorá sa použije. Relačné databázy sú zjednodušene ideálne pre ukladanie čísiel, informácií o zákazníkoch a objednávkach, výrobkoch, všade kde treba vytvárať rôzne reporty, prehľady a rôznymi

95 KAPITOLA 8: TESTOVANIE spôsobmi dáta agregovať. Typické použitie sú banky a iné finančné inštitúcie, továrne a pod. Objektové databázy sú zasa výhodné pre ukladanie modelu reprezentujúceho časť reálneho sveta. NoSQL databázy sa začínajú presadzovať až v poslednej dobe, vďaka neukladaniu dát v podobe relácií veľmi dobre spolupracujú s objektovo orientovanými jazykmi. Vďaka jednoduchej možnosti horizontálneho škálovania sú ideálne pre moderné webové aplikácie pracujúce s terabajtami dát. Pre ukladanie veľkého množstva n-tíc, kde je najčastejšie jednoduché vyhľadávanie a dáta sú neštruktúrované je ideálne použitie databázy typu kľúč-hodnota. Dokumentová databáza je vhodná pre dáta, ktoré so sebou súvisia a nie je treba z nich vytvárať reporty, napr. systémy na uchovávanie kontaktov, webové stránky, blogy a pod. V praxi použiteľnou voľbou môže byť vhodná kombinácia rôznych databáz na rôzne časti systému zameraného na obchod: Finančné dáta uložené v správne navrhnutej relačnej databáze, katalóg produktov v databáze dokumentovej, odporúčania v grafovej a aktivita užívateľov v stĺpcovo orientovanej a nákupný košík v databáze typu kľúč- hodnota. [58]

96 Kapitola 9 Záver

Čitateľovi táto práca ponúkla komplexný pohľad na objektovo-relačné mapovanie na platforme .NET. Cieľom úvodných kapitol bolo vysvetlenie základných termínov a odlišností medzi relačným a objektovým prístupom v pohľade na dáta. Následne bol čitateľ zoznámený s problematikou objektovo-relačného mapovania a s postupmi a návrhovými vzormi, ktoré sú pri tvorbe týchto nástrojov používané. Šiesta kapitola ponúka aktuálny prehľad použiteľných ORM na platforme .NET. Nasledujúce kapitoly popisujú najpopulárnejšie nástroje (Entity Framework, LINQ to SQL, NHibernate a LLBLGen Pro), porovnávajú ich s použitím „klasického“ dopytovania pomocou ADO.NET a s použitím NoSQL databázy. Aktuálne verzie sú otestované v mnohých rôznych situáciách a získané výsledky sú prezentované v grafoch, tabuľkách a ukážkach zdrojových kódov. Čitateľ po prečítaní tejto práce získal aktuálny prehľad problematiky ORM na platforme .NET a nadobudnuté znalosti mu pomôžu vo výbere vhodného nástroja pre riešenie konkrétneho problému.

9.1.1 Názor autora Pri štúdiu problematiky a pri práci s uvedenými nástrojmi ma príjemne prekvapilo množstvo vecí. NoSQL databáza RavenDB je na použitie najjednoduchšia zo všetkých nástrojov, po počiatočnom zoznámení s webovou prezentáciou je možné okamžite vyvíjať vlastnú aplikáciu a o dátovú vrstvu sa takmer vôbec „nestarať“. Rýchlosť je pre malé projekty dostatočná, komunita okolo je aktívna a ďalšie verzie databázy budú určite výkonnejšie a s ďalšou pridanou funkcionalitou. Spôsob dopytovania pomocou LINQ je podľa môjho názoru budúcnosťou pre .NET platformu. Programátor sa nemusí učiť nové spôsoby dopytovania napr. pre XML, zároveň môže znalosť LINQ využiť v rôznych ORM nástrojoch s funkčným LINQ poskytovateľom. V tomto smere bolo nemilým prekvapením LINQ to NHibernate, ktoré oproti iným nástrojom viditeľne zaostáva vo funkcionalite a aj v zdrojoch informácií na Internete. Na druhú stranu použitie jazyka HQL prináša značnú rýchlosť a pri aplikáciách s dôrazom na výkon ho rozhodne odporúčam. Literatúra a celkovo podpora sa mi zdala trochu horšia, v porovnaní s ostatnými nástrojmi. Entity Framework a LINQ to SQL sú v podstate na LINQ založené a podporujú ho príkladne. U EF je vidieť ako sa Microsoft snaží dostať túto technológiu do popredia, je k dispozícii jednoznačne najlepšia podpora na fórach, najväčší počet návodov a videí. Dokonca v poslednej verzii je kód EF verejne prístupný ako open-source (rovnako ako napríklad nedávno uverejnený framework ASP MVC), čo v minulosti rozhodne nebolo pre Microsoft technológie bežné. LINQ to SQL je síce neaktívny projekt, ale keďže je nedielnou súčasťou platformy .NET, tak je stále možné ho použiť a na malé a jednoduché projekty je ideálny. Posledným z testovaných bol komerčný nástroj LLBLGen Pro, ktorý má výborne spracovaný manuál s obrovským množstvom informácií, príkladov a ukážok zdrojových 97 KAPITOLA 9: ZÁVER kódov. Tu je vidieť, že firma predáva komplexný a vyspelý produkt a patrične si za neho nechá zaplatiť. Informácií na Internete je menej, zrejme z dôvodu komerčnej podpory. Z hľadiska tvorby modelu a mapovania bol Designer LLBLGen Pro najlepší, aj keď z počiatku mi prišiel veľmi komplikovaný a ťažkopádny. Všetky použité nástroje (ORM a RavenDB) ponúkajú v rámci zdrojového kódu mierne odlišný spôsob práce s dátami, ktorý je podstatne pohodlnejší ako klasické ADO.NET. Na začiatku je nutné venovať štúdiu danej problematiky množstvo času, ktoré sa neskôr vráti ako úspora pri vývoji a udržovaniu aplikácie.

98 Literatúra

[1] FINLEY, Klint. 5 Ways to Tell Which Programming Languages are Most Popular. In: ReadWrite [online]. 2012-06-05 [cit. 2013-05-05]. Dostupné z: http://readwrite.com/2012/06/05/5-ways-to-tell-which-programming-lanugages-are-most- popular [2] Database Management - History Of Database Management. In: Free Encyclopedia of Ecommerce [online]. [cit. 2013-05-06]. Dostupné z: http://ecommerce.hostip.info/pages/295/Database-Management-HISTORY-DATABASE- MANAGEMENT.html [3] QUASSNOI. What is a relational database?. In: EXPLAIN EXTENDED [online]. 2009-08-23 [cit. 2013-05-06]. Dostupné z: http://explainextended.com/2009/08/23/what-is-a-relational- database/ [4] CODD, E. F. A relational model of data for large shared data banks. Communications of the ACM . 1983, vol. 26, issue 1, s. 64-69. DOI: 10.1145/357980.358007. [5] DAVIDSON, Louis a Jessica MOSS. Pro SQL server 2012 relational database design and implementation . New York: Apress, c2012, xxxi, 751 p. ISBN 14-302-3695-7. [6] CODD, E.F. The twelve rules for relational DBMS . San Jose, the Relational Institute, Technical Report EFC-6, 1986 [7] ITOI BLOMGREN, Michiko. Are SQL Server, DB2, and Oracle really relational? Göteborg, 2003-05-27. Diplomová práca. Göteborgs universitet, Handelshögskolan. Vedoucí práce Alan B. Carlson. [8] CHAPPLE, Mike. Top 5 Desktop Databases. In: About.com [online]. [cit. 2013-05-06]. Dostupné z: http://databases.about.com/od/administration/tp/topdesktopdbs.htm

[9] Most Widely Deployed SQL Database. SQLite [online]. [cit. 2013-05-06]. Dostupné z: http://www.sqlite.org/mostdeployed.html

[10] CODD, E. The relational model for database management: version 2 . Reading, Mass.: Addison- Wesley, c1990, xxii, 538 p. ISBN 02-011-4192-2.

[11] GARCIA-MOLINA, Hector, Jeffrey D ULLMAN a Jennifer WIDOM. Database systems: the complete book . 2nd ed. Upper Saddle River, N.J.: Pearson Prentice Hall, c2009, xxxvi, 1203 p. ISBN 01-318-7325-3. [12] SILBERSCHATZ, Abraham, Henry F KORTH a S SUDARSHAN. Database system concepts . 6th ed. New York: McGraw-Hill, c2011, xxvi, 1349 p. ISBN 00-712-8959-3. [13] DATE, C.J. SQL and relational theory: how to write accurate SQL code . 2nd ed. Farnham: O'Reilly, 2009. ISBN 978-144-9316-402.

[14] POWELL, Gavin. Beginning database design . Indianapolis, IN: Wiley, c2006, xxiii, 467 p. ISBN 978-076-4574-900.

99 LITERATÚRA [15] STRAMBA, Slavomír. FAKULTA ELEKTROTECHNIKY A INFORMATIKY,. Relačná algebra . Košice. 2003. Dostupné z: http://hornad.fei.tuke.sk/~genci/Vyucba/SRBDp/2003- 2004/07- SpracovanieDotazov&Optimalizacia/Rajchman/Implementacia%20relacnej%20algebry/prezent acia/Algebra.ppt

[16] Object Database Management Systems [online]. [cit. 2013-05-06]. Dostupné z: http://www.odbms.org/

[17] SADALAGE, Pramod J a Martin FOWLER. NoSQL distilled: a brief guide to the emerging world of polyglot persistence . Upper Saddle River, NJ: Addison-Wesley, c2013, xix, 164 p. ISBN 03-218-2662-0.

[18] CHANG, Fay, Jeffrey DEAN, Sanjay GHEMAWAT, Wilson C. HSIEH, Deborah A. WALLACH, Mike BURROWS, Tushar CHANDRA, Andrew FIKES a Robert E. GRUBER. GOOGLE, Inc. Bigtable: A Distributed Storage System for Structured Data . 2006.

[19] GILBERT, Seth a Nancy LYNCH. Brewer's conjecture and the feasibility of consistent, available, partition-tolerant web services. ACM SIGACT News. 2002, vol. 33, issue 2. DOI: 10.1145/564585.564601.

[20] BOOCH, Grady a Grady BOOCH. Object-oriented analysis and design with applications . 3rd ed. Upper Saddle River, NJ: Addison-Wesley, c2007, xxiii, 691 p. ISBN 978-020-1895-513. [21] OOP. In: TechTerms.com [online]. 2007-11-02 [cit. 2013-05-06]. Dostupné z: http://www.techterms.com/definition/oop [22] MEYER, Bertrand. Object-oriented software construction . 2nd ed. Upper Saddle River: Prentice Hall, 1997, xxvii, 1254 s. ISBN 01-362-9155-4. [23] ARMSTRONG, Deborah J. The quarks of object-oriented development. Communications of the ACM . 2006, vol. 49, issue 2, s. 123-128. DOI: 10.1145/1113034.1113040. [24] FUSSEL, Mark L. Foundations of Object-Relational Mapping; White Paper ; ChiMu Corp. 1997. [25] WEISFELD, Matt A. The object-oriented thought process . 3rd ed. Upper Saddle River: Addison-Wesley, c2009, xii, 330 s. Developer's library. ISBN 978-0-672-33016-2. [26] MAKESH. Association, Aggregation, Composition. In: Geeks with blogs.NET [online]. 2006-11- 03 [cit. 2013-05-06]. Dostupné z: http://geekswithblogs.net/mahesh/archive/2006/11/03/95960.aspx [27] HAACK, Phil. The meaning of "Impedance Mismatch". In: Haacked [online]. 2004-06-14 [cit. 2013-05-06]. Dostupné z: http://haacked.com/archive/2004/06/15/impedance-mismatch.aspx [28] AMBLER, Scott W. Agile database techniques: effective strategies for the agile software developer . Indianapolis: Wiley Publishing, 2003, xxvii, 447 s. ISBN 04-712-0283-5. [29] FOWLER, Martin. Patterns of enterprise application architecture . Boston: Addison-Wesley, c2003, xxiv, 533 p. ISBN 03-211-2742-0.

100 LITERATÚRA [30] GAMMA, Erich. Design patterns CD: elements of reusable object-oriented software . Reading: Addison-Wesley Professional Computing Series, c1995, 1 CD-ROM. ISBN 02-016-3498-8. [31] BISHOP, J. C#: návrhové vzory . Vyd. 1. Brno: Zoner Press, 2010, 323 s. ISBN 978-80-7413- 076-2. [32] .NET. MICROSOFT. Microsoft [online]. [cit. 2013-05-06]. Dostupné z: http://www.microsoft.com/net [33] List of CLI languages. In: Wikipedia: the free encyclopedia [online]. San Francisco (CA): Wikimedia Foundation, 2013-04-11 [cit. 2013-05-06]. Dostupné z: http://en.wikipedia.org/wiki/List_of_CLI_languages [34] PATRICK, Tim. Microsoft ADO.NET 4 step by step . Sebastopol, Calif.: O'Reilly Media, c2010, xxiii, 411 p. ISBN 07-356-3888-8. [35] Guidance on Differences Between WPF and Silverlight [online]. [cit. 2013-05-06]. Dostupné z: http://wpfslguidance.codeplex.com/ [36] HALL, Gary McLean. Pro WPF and Silverlight MVVM: effective application development with Model-View-ViewModel . New York: Distributed to the book trade worldwide by Springer Science Business Media, c2010, xiii, 257 p. Expert's voice in WPF. ISBN 14-302-3162-9. [37] Comega. MICROSOFT RESEARCH. [online]. [cit. 2013-05-06]. Dostupné z: http://research.microsoft.com/en-us/um/cambridge/projects/comega/ [38] MARGUERIE, Fabrice, Steve EICHERT a Jim WOOLEY. LINQ in action . Greenwich, CT: Manning, c2008, xxvii, 542 p. ISBN 978-193-3988-160. [39] The .NET Standard Query Operators. HEJLSBERG, Anders a Mads MADS. MICROSOFT. Msdn.microsoft.com [online]. [cit. 2013-05-21]. Dostupné z: http://msdn.microsoft.com/en- us/library/bb394939.aspx [40] CALVERT, Charlie. Link to Everything: A List of LINQ Providers. Charlie Calvert's Community Blog [online]. 2008-02-28 [cit. 2013-05-21]. Dostupné z: http://blogs.msdn.com/b/charlie/archive/2008/02/28/link-to-everything-a-list-of-linq- providers.aspx [41] RavenDB Documentation [online]. [cit. 2013-05-21]. Dostupné z: http://ravendb.net/docs [42] List of object-relational mapping software. In: Wikipedia: the free encyclopedia [online]. San Francisco (CA): Wikimedia Foundation, 2013-04-22 [cit. 2013-05-21]. Dostupné z: http://en.wikipedia.org/wiki/List_of_object-relational_mapping_software [43] ADO .NET Entity Framework Vote of No Confidence. [online]. [cit. 2013-05-21]. Dostupné z: http://efvote.wufoo.com/forms/z7x3p9/ [44] Microsoft open-sources Entity Framework. In: KRILL, Paul. InfoWorld [online]. 2012-07-20 [cit. 2013-05-21]. Dostupné z: http://www.infoworld.com/d/application- development/microsoft-open-sources-entity-framework-198213 [45] ADO.NET Data Providers. Msdn.microsoft.com [online]. [cit. 2013-05-21]. Dostupné z: http://msdn.microsoft.com/en-us/data/dd363565.aspx [46] Entity Framework Overview. Msdn.microsoft.com [online]. 2012-08-02 [cit. 2013-05-21]. Dostupné z: http://msdn.microsoft.com/en-us/library/bb399567.aspx 101 LITERATÚRA [47] Auto-Compiled LINQ Queries (Entity Framework June 2011 CTP). MICROSOFT. Entity Framework Design [online]. 2011-06-30 [cit. 2013-05-21]. Dostupné z: http://blogs.msdn.com/b/efdesign/archive/2011/06/30/auto-compiled-linq-queries-entity- framework-june-2011-ctp.aspx [48] JULIA LERMAN, Rowan Miller. Programming entity framework . Farnham: O'Reilly, c2012. ISBN 978-144-9312-961. [49] LERMAN, Julia. Programming Entity framework . 2nd ed. Sebastopol: O´Reilly, c2010, xxxvi, 873 s. ISBN 978-0-596-80726-9. [50] The Origin of LINQ to SQL. WARREN, Matt. The Wayward WebLog [online]. 2007-05-31 [cit. 2013-05-21]. Dostupné z: http://blogs.msdn.com/b/mattwar/archive/2007/05/31/the-origin-of- linq-to-sql.aspx [51] FREEMAN Adam, Joseph C. RATTZ, Adam Freeman and Joseph C.Jr a Technical reviewer: Fabio Claudio FERRACCHIATI. Pro LINQ language integrated query in C ♯ 2010 . New York: Apress, 2010. ISBN 978-143-0226-543. [52] Project Summary. NHibernate [online]. [cit. 2013-05-21]. Dostupné z: http://www.ohloh.net/p/nhibernate [53] NHibernate Reference Documentation. NHibernate - Relational Persistence for Idiomatic .NET [online]. 2013 [cit. 2013-05-21]. Dostupné z: http://nhforge.org/doc/nh/en/index.html [54] KUATÉ, Pierre Henri. NHibernate in action . Greenwich: Manning, c2009, xxix, 367 p. ISBN 19-323-9492-3. [55] PERKINS, Benjamin. Working with NHibernate 3.0 . Indianapolis, Ind: John Wiley. ISBN 978- 111-8104-606. [56] Some of our customers. LLBLGen Pro [online]. [cit. 2013-05-21]. Dostupné z: http://www.llblgen.com/pages/customers.aspx [57] Overview. LLBLGen Pro [online]. [cit. 2013-05-21]. Dostupné z: http://www.llblgen.com/pages/overview.aspx [58] FOWLER, Martin. NoSQL Distilled to an hour. In: Vimeo [online video]. 2013-05-13 [cit. 2013- 05-22]. Dostupné z: http://vimeo.com/66052102

102 LITERATÚRA Zoznam obrázkov

Obrázok 3.1: Dedičnosť ...... 16 Obrázok 3.2: Polymorfizmus ...... 16 Obrázok 3.3: Typy vzťahov medzi objektami ...... 17 Obrázok 3.4: Násobnosti vo vzťahoch...... 18 Obrázok 4.1: Násobnosti objektového modelu ...... 22 Obrázok 4.2: Násobnosti relačného modelu ...... 22 Obrázok 4.3: Tabuľka Osoba ...... 25 Obrázok 4.4: Brána k dátam tabuľky ...... 26 Obrázok 4.5: Brána k dátam riadku ...... 26 Obrázok 4.6: Aktívny záznam ...... 27 Obrázok 4.7: Mapovač dát...... 27 Obrázok 4.8: Mapa identity ...... 28 Obrázok 4.9: Pracovná jednotka ...... 29 Obrázok 4.10: Lenivé nahrávanie ...... 29 Obrázok 4.11: Ukážková hierarchia dedičnosti ...... 30 Obrázok 4.12: Dedičnosť jednej tabuľky ...... 31 Obrázok 4.13: Dedičnosť tabuľky triedy ...... 32 Obrázok 4.14: Dedičnosť konkrétnej tabuľky ...... 32 Obrázok 4.15: Mapovače dedičnosti ...... 33 Obrázok 4.16: Generická štruktúra tabuliek ...... 34 Obrázok 4.17: Pole identity ...... 35 Obrázok 4.18: Mapovanie cudzích kľúčov ...... 35 Obrázok 4.19: Mapovanie asociačnej tabuľky ...... 36 Obrázok 4.20: Mapovanie závislosti ...... 36 Obrázok 4.21: Zabudovaná hodnota ...... 37 Obrázok 4.22: Serializovaný BLOB ...... 38 Obrázok 4.23: Mapovanie metadát ...... 38 Obrázok 4.24: Dopytovací objekt ...... 39 Obrázok 4.25: Repozitár ...... 40 Obrázok 7.1: Entity Framework architektúra ...... 60 Obrázok 7.2: Projekcie ...... 79 Obrázok 7.3: Model podľa databázy ...... 80 Obrázok 7.4: Databáza podľa modelu ...... 81 Obrázok 8.1: Aplikácia ORM Test ...... 83 Obrázok 8.2: Počty dokumentov v NoSQL databáze NorthPV ...... 84 Obrázok 8.3: Ukážka výsledkov merania ...... 87 Obrázok 9.1: Diagram databáze „North“ ...... 105 Obrázok 9.2: Diagram časti databáze „PV“ ...... 106

103 LITERATÚRA Zoznam tabuliek

Tabuľka 2.1: Inštancia relácie Predmety...... 5 Tabuľka 2.2: Relácia T ...... 6 Tabuľka 2.3: Relácia U ...... 6 Tabuľka 2.4: Relácia V ...... 6 Tabuľka 2.5: Výsledok projekcie ...... 6 Tabuľka 2.6: Výsledok selekcie...... 6 Tabuľka 2.7: Výsledok karteziánskeho súčinu ...... 7 Tabuľka 2.8: Výsledok zjednotenia ...... 7 Tabuľka 2.9: Výsledok rozdielu ...... 7 Tabuľka 2.10: Relácia T ako výsledok premenovania ...... 8 Tabuľka 4.1: Rozdiely medzi objektovým a relačným svetom ...... 20 Tabuľka 4.2: Mapovanie vlastností ...... 23 Tabuľka 4.3: Detaily mapovania ...... 24 Tabuľka 8.1: Počty riadkov v tabuľkách relačnej databáze NorthPV ...... 84 Tabuľka 10.1: Prvá časť výsledkov ORM Test ...... 132 Tabuľka 10.2: Druhá časť výsledkov ORM Test ...... 133 Tabuľka 10.3: Prvá časť výsledkov zápisu ProteinLite ...... 134 Tabuľka 10.4: Druhá časť výsledkov zápisu ProteinLite ...... 135 Tabuľka 10.5: Výsledky načítavania ProteinLite ...... 136

Zoznam grafov

Graf 8.1: Výsledky testov načítavania ...... 88 Graf 8.2: Výsledky testov načítavania ...... 89 Graf 8.3: Výsledky testu načítavania ...... 89 Graf 8.4: Výsledky testov manipulácie s dátami ...... 90 Graf 8.5: Výsledok testu vytvárania kontextu ...... 90 Graf 8.6: Výsledok testu inicializácie nástrojov ...... 91 Graf 8.7: Výsledky manipulácie s dátami vo vláknach ...... 91 Graf 8.8: Porovnanie zápisu č.1 ...... 93 Graf 8.9: Porovnanie zápisu č.2 ...... 94 Graf 8.10: Porovnanie načítavania ...... 94

104 PRÍLOHY Prílohy

Príloha A: Diagramy databáz

Obrázok 9.1: Diagram databáze „North“

105 PRÍLOHY

Obrázok 9.2: Diagram časti databáze „PV“

106 PRÍLOHY Príloha B: Zdrojové kódy testovacích dopytov

Nasledujú jednotlivé záznamy pre každý z testovaných nástrojov aplikácie ORM Test, zdrojový kód ich dopytu a transformácia na SQL dopyt z monitorovacieho programu SQL Server Profiler. V prípade databáze RavenDB sú uvedené zdrojové kódy dopytu a indexu z aplikácie a LINQ zdrojový kód indexu tak ako ho databáza interne uchováva.

1. SelectPV1_Glass

ADO.NET // Zdrojový kód: string sqlString = @"SELECT GlassID, WoID FROM NorthPV.dbo.Glasses WHERE IdealWatt = @IdealWatt"; // SQL Server Profiler: exec sp_executesql N'SELECT GlassID, WoID FROM NorthPV.dbo.Glasses WHERE IdealWatt = @IdealWatt',N'@IdealWatt int',@IdealWatt=260

Entity Framework // Zdrojový kód: var glasses = context.Glasses .Where(g => g.IdealWatt == "260" ) .Select(x => new { GlassId = x.GlassID, WoID = x.WoID }); // SQL Server Profiler: SELECT 1 AS [C1], [Extent1].[GlassID] AS [GlassID], [Extent1].[WoID] AS [WoID] FROM [dbo].[Glasses] AS [Extent1] WHERE '260' = [Extent1].[IdealWatt]

LINQ to SQL // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler exec sp_executesql N'SELECT [t0].[GlassID] AS [GlassId], [t0].[WoID] FROM [dbo].[Glasses] AS [t0] WHERE [t0].[IdealWatt] = @p0',N'@p0 varchar(8000)',@p0='260'

LLBLGen Pro // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: exec sp_executesql N'SELECT [LPLA_1].[GlassID], [LPLA_1].[WoID] FROM [NorthPV].[dbo].[Glasses] [LPLA_1] WHERE ( ( ( ( [LPLA_1].[IdealWatt] = @p1))))',N'@p1 varchar(16)',@p1='260'

NHibernate (HQL) // Zdrojový kód: var query = session.CreateQuery (@"SELECT g.GlassID, g.WoID FROM Glass g WHERE g.IdealWatt = :_IdealWatt" );

107 PRÍLOHY // SQL Server Profiler: exec sp_executesql N'select glass0_.GlassID as col_0_0_, glass0_.WoID as col_1_0_ from dbo.Glasses glass0_ where glass0_.IdealWatt=@p0',N'@p0 nvarchar(4000)',@p0=N'260'

NHibernate (LINQ) // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: // Vygenerovaný SQL dopyt je rovnaký ako v prípade NHibernate HQL

RavenDB // Zdrojový kód dopytu: var glasses = ( from glass in session.Query< RavenGlass , RavenGlasses_ByIdealWatt >() where glass.IdealWatt == "260" select new { GlassID = glass.GlassID, WoID = glass.WoID }).Take(512); // Zdrojový kód indexu: public class RavenGlasses_ByIdealWatt : AbstractIndexCreationTask { public RavenGlasses_ByIdealWatt() { Map = glasses => from glass in glasses select new { IdealWatt = glass.IdealWatt }; } } // Index na serveri: // Map docs.RavenGlasses.Select(glass => new { IdealWatt = glass.IdealWatt })

2. SelectPV2_Glass_Procedure

ADO.NET // Zdrojový kód: string sqlString = @"SELECT Glass BY IdealWatt"; // SQL Server Profiler: exec SELECT Glass BY IdealWatt @IdealWatt=260

Entity Framework // Zdrojový kód: var glasses = context.Select_Glass_by_IdealWatt( "260" ); // SQL Server Profiler: exec [dbo].[Select Glass by IdealWatt] @IdealWatt='260'

LINQ to SQL // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku // SQL Server Profiler: declare @p4 int set @p4=0 exec sp_executesql N'EXEC @RETURN_VALUE = [dbo].[Select Glass by IdealWatt] @IdealWatt = @p0',N'@p0 varchar(8000),@RETURN_VALUE int output',@p0='260',@RETURN_VALUE=@p4 output select @p4 108 PRÍLOHY LLBLGen Pro // Zdrojový kód: var reader = adapter.FetchDataReader( RetrievalProcedures . GetSelectGlassByIdealWattCallAsQuery( "260" ), CommandBehavior .CloseConnection); // SQL Server Profiler: exec [NorthPV].[dbo].[Select Glass by IdealWatt] @IdealWatt='260'

NHibernate (HQL) // Zdrojový kód: var glasses = session.GetNamedQuery( "SelectGlassbyIdealWatt" ); // SQL Server Profiler: exec sp_executesql N'exec dbo.[Select Glass by IdealWatt] @p0',N'@p0 nvarchar(4000)',@p0=N'260'

NHibernate (LINQ) // Zdrojový kód: // NHibernate LINQ nepodporuje volanie databázových procedúr

RavenDB // Zdrojový kód dopytu: // RavenDB nepodporuje volanie databázových procedúr

3. SelectPV3_Glass_Stringer

ADO.NET // Zdrojový kód: string sqlString = @"SELECT DISTINCT g.GlassID FROM NorthPV.dbo.Glasses g INNER JOIN NorthPV.dbo.Stringers s ON g.GlassID = s.GlassID WHERE g.PartNo = @PartNo AND s.CreateTime > @CreateTime"; // SQL Server Profiler: exec sp_executesql N'SELECT DISTINCT g.GlassID FROM NorthPV.dbo.Glasses g INNER JOIN NorthPV.dbo.Stringers s ON g.GlassID = s.GlassID WHERE g.PartNo = @PartNo AND s.CreateTime > @CreateTime', N'@PartNo nvarchar(12),@CreateTime nvarchar(23)', @PartNo=N'9B.M2P09.102', @CreateTime=N'2013-03-04 00:00:00.000'

Entity Framework // Zdrojový kód: var glasses = (context.Glasses .Join(context.Stringers, g => g.GlassID, s => s.GlassID, (g, s) => new { g = g, s = s }) .Where(x => ((x.g.PartNo == "9B.M2P09.102" ) && (x.s.CreateTime > new DateTime (2013, 03, 04, 0, 0, 0, 0)))) .Select(x => new { GlassID = x.g.GlassID })).Distinct(); // SQL Server Profiler: SELECT [Distinct1].[C1] AS [C1], [Distinct1].[GlassID] AS [GlassID] FROM ( SELECT DISTINCT [Extent1].[GlassID] AS [GlassID], 1 AS [C1] 109 PRÍLOHY FROM [dbo].[Glasses] AS [Extent1] INNER JOIN [dbo].[Stringers] AS [Extent2] ON [Extent1].[GlassID] = [Extent2].[GlassID] WHERE ('9B.M2P09.102' = [Extent1].[PartNo]) AND ([Extent2].[CreateTime] > convert(datetime2, '2013-03-04 00:00:00.0000000', 121)) ) AS [Distinct1]

LINQ to SQL // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: exec sp_executesql N'SELECT DISTINCT [t0].[GlassID] FROM [dbo].[Glasses] AS [t0] INNER JOIN [dbo].[Stringers] AS [t1] ON [t0].[GlassID] = [t1].[GlassID] WHERE ([t0].[PartNo] = @p0) AND ([t1].[CreateTime] > @p1)',N'@p0 varchar(8000), @p1 datetime',@p0='9B.M2P09.102',@p1='2013-03-04 00:00:00'

LLBLGen Pro // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: exec sp_executesql N'SELECT DISTINCT [LPA_L1].[GlassID] FROM ( [NorthPV].[dbo].[Glasses] [LPA_L1] INNER JOIN [NorthPV].[dbo].[Stringers] [LPA_L2] ON [LPA_L1].[GlassID] = [LPA_L2].[GlassID]) WHERE (((((([LPA_L1].[PartNo] = @p1) AND ( [LPA_L2].[CreateTime] > @p2))))))', N'@p1 varchar(32),@p2 datetime',@p1='9B.M2P09.102',@p2='2013-03-04 00:00:00'

NHibernate (HQL) // Zdrojový kód: var query = session.CreateQuery( @"SELECT DISTINCT g.GlassID FROM Glass g JOIN g.Stringers s WHERE g.PartNo = :_PartNo AND s.CreateTime > :_CreateTime" ); // SQL Server Profiler: exec sp_executesql N'select distinct glass0_.GlassID as col_0_0_ from dbo.Glasses glass0_ inner join dbo.Stringers stringers1_ on glass0_.GlassID=stringers1_.GlassID where glass0_.PartNo=@p0 and stringers1_.CreateTime>@p1',N'@p0 nvarchar(4000), @p1 datetime',@p0=N'9B.M2P09.102',@p1='2013-03-04 00:00:00'

NHibernate (LINQ) // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: // Vygenerovaný SQL dopyt je rovnaký ako v prípade NHibernate HQL

110 PRÍLOHY RavenDB // Zdrojový kód dopytu: var glasses = session .Query< RavenGlass , RavenGlasses_ByPartNoStringerCreateTime >() .Where(x => x.PartNo == "9B.M2P09.102" ) .Where(x => x.CreateTime > new DateTime (2013, 03, 04, 0, 0,0, 0)) .Select(x => x);

// Zdrojový kód indexu: public class RavenGlasses_ByPartNoStringerCreateTime : AbstractIndexCreationTask { public class MapResult { public string GlassID { get ; set ; } public string PartNo { get ; set ; } public DateTime ? CreateTime { get ; set ; } }

public RavenGlasses_ByPartNoStringerCreateTime() { Map = glasses => from glass in glasses from stringer in glass.RavenStringers select new { GlassID = glass.GlassID, PartNo = glass.PartNo, CreateTime = stringer.CreateTime };

Reduce = results => from result in results group result by new { result.GlassID, result.PartNo, result.CreateTime } into g select new { GlassID = g.Key.GlassID, PartNo = g.Key.PartNo, CreateTime = g.Key.CreateTime }; }

// Index na serveri: // Map docs.RavenGlasses .SelectMany(glass => glass.RavenStringers, (glass, stringer) => new { GlassID = glass.GlassID, PartNo = glass.PartNo, CreateTime = ((DateTime ? ) stringer.CreateTime) })

// Reduce results.GroupBy(result => new { GlassID = result.GlassID, PartNo = result.PartNo, CreateTime = ((DateTime ? ) result.CreateTime) }) .Select(g => new { GlassID = g.Key.GlassID, PartNo = g.Key.PartNo, CreateTime = g.Key.CreateTime })

111 PRÍLOHY 4. SelectPV4_GlassAll_Stringer

ADO.NET // Zdrojový kód: string sqlString = @"SELECT DISTINCT g.GlassID, g.WoID, g.LineID, g.MtrlPartNo, g.IdealWatt, g.StationID, g.CartonNo, g.CustCartonNo, g.MrNo, g.CustShippingNo2, s.CreateTime FROM NorthPV.dbo.Glasses g LEFT JOIN NorthPV.dbo.Stringers s ON g.GlassID = s.GlassID WHERE g.PartNo = @PartNo AND s.CreateTime > @CreateTime" ; // SQL Server Profiler: exec sp_executesql N'SELECT DISTINCT g.GlassID, g.WoID, g.LineID, g.MtrlPartNo, g.IdealWatt, g.StationID, g.CartonNo, g.CustCartonNo, g.MrNo, g.CustShippingNo2, s.CreateTime FROM NorthPV.dbo.Glasses g LEFT JOIN NorthPV.dbo.Stringers s ON g.GlassID = s.GlassID WHERE g.PartNo = @PartNo AND s.CreateTime > @CreateTime',N'@PartNo nvarchar(12),@CreateTime nvarchar(23)',@PartNo=N'9B.M2P09.102',@CreateTime=N'2013-03-04 00:00:00.000'

Entity Framework // Zdrojový kód: var glasses = (context.Glasses .Join(context.Stringers, g => g.GlassID, s => s.GlassID, (g, s) => new { g = g, s = s }) .Where(x => ((x.g.PartNo == "9B.M2P09.102" ) && (x.s.CreateTime > new DateTime (2013, 03, 04, 0, 0, 0, 0)))) .Select(x => new { GlassID = x.g.GlassID, WoID = x.g.WoID, LineID = x.g.LineID, MtrlPartNo = x.g.MtrlPartNo, IdealWatt = x.g.IdealWatt, StationID = x.g.StationID, CartonNo = x.g.CartonNo, CustCartNo = x.g.CustCartonNo, MrNo = x.g.MrNo, CustShippingNo2 = x.g.CustShippingNo2, CreateTime = x.s.CreateTime })).Distinct(); // SQL Server Profiler: SELECT [Distinct1].[C1] AS [C1], [Distinct1].[GlassID] AS [GlassID], [Distinct1].[WoID] AS [WoID], [Distinct1].[LineID] AS [LineID], [Distinct1].[MtrlPartNo] AS [MtrlPartNo], [Distinct1].[IdealWatt] AS [IdealWatt],[Distinct1].[StationID] AS [StationID], [Distinct1].[CartonNo] AS [CartonNo], [Distinct1].[CustCartonNo] AS [CustCartonNo], [Distinct1].[MrNo] AS [MrNo], [Distinct1].[CustShippingNo2] AS [CustShippingNo2], [Distinct1].[CreateTime] AS [CreateTime] FROM ( SELECT DISTINCT [Extent1].[GlassID] AS [GlassID], [Extent1].[WoID] AS [WoID], [Extent1].[LineID] AS [LineID], [Extent1].[StationID] AS [StationID], [Extent1].[CartonNo] AS [CartonNo], [Extent1].[CustCartonNo] AS [CustCartonNo], [Extent1].[MrNo] AS [MrNo], [Extent1].[CustShippingNo2] AS [CustShippingNo2], [Extent1].[IdealWatt] AS [IdealWatt], [Extent1].[MtrlPartNo] AS [MtrlPartNo], [Extent2].[CreateTime] AS [CreateTime], 1 AS [C1] 112 PRÍLOHY FROM [dbo].[Glasses] AS [Extent1] INNER JOIN [dbo].[Stringers] AS [Extent2] ON [Extent1].[GlassID] = [Extent2].[GlassID] WHERE ('9B.M2P09.102' = [Extent1].[PartNo]) AND ([Extent2].[CreateTime] > convert(datetime2, '2013-03-04 00:00:00.0000000', 121)) ) AS [Distinct1]

LINQ to SQL // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: exec sp_executesql N'SELECT DISTINCT [t0].[GlassID], [t0].[WoID], [t0].[LineID], [t0].[MtrlPartNo], [t0].[IdealWatt], [t0].[StationID], [t0].[CartonNo], [t0].[CustCartonNo] AS [CustCartNo], [t0].[MrNo], [t0].[CustShippingNo2], [t1].[CreateTime] FROM [dbo].[Glasses] AS [t0] INNER JOIN [dbo].[Stringers] AS [t1] ON [t0].[GlassID] = [t1].[GlassID] WHERE ([t0].[PartNo] = @p0) AND ([t1].[CreateTime] > @p1)',N'@p0 varchar(8000), @p1 datetime',@p0='9B.M2P09.102',@p1='2013-03-04 00:00:00'

LLBLGen Pro // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: exec sp_executesql N'SELECT DISTINCT [LPA_L1].[GlassID], [LPA_L1].[WoID], [LPA_L1].[LineID], [LPA_L1].[MtrlPartNo], [LPA_L1].[IdealWatt], [LPA_L1].[StationID], [LPA_L1].[CartonNo], [LPA_L1].[CustCartonNo], [LPA_L1].[MrNo], [LPA_L1].[CustShippingNo2], [LPA_L2].[CreateTime] FROM ( [NorthPV].[dbo].[Glasses] [LPA_L1] INNER JOIN [NorthPV].[dbo].[Stringers] [LPA_L2] ON [LPA_L1].[GlassID] = [LPA_L2].[GlassID]) WHERE ( ( ( ( ( ( [LPA_L1].[PartNo] = @p1) AND ( [LPA_L2].[CreateTime] > @p2))))))',N'@p1 varchar(32), @p2 datetime',@p1='9B.M2P09.102',@p2='2013-03-04 00:00:00'

NHibernate (HQL) // Zdrojový kód: var query = session .CreateQuery( @"SELECT DISTINCT g.GlassID, g.WoID, g.LineID, g.MtrlPartNo, g.IdealWatt, g.StationID, g.CartonNo, g.CustCartonNo, g.MrNo, g.CustShippingNo2, s.CreateTime FROM Glass g JOIN g.Stringers s WHERE g.PartNo = :_PartNo AND s.CreateTime > :_CreateTime"); // SQL Server Profiler: exec sp_executesql N'select distinct glass0_.GlassID as col_0_0_, glass0_.WoID as col_1_0_, glass0_.LineID as col_2_0_, glass0_.MtrlPartNo as col_3_0_, glass0_.IdealWatt as col_4_0_, glass0_.StationID as col_5_0_, glass0_.CartonNo as col_6_0_, glass0_.CustCartonNo as col_7_0_, glass0_.MrNo as col_8_0_, glass0_.CustShippingNo2 as col_9_0_, stringers1_.CreateTime as col_10_0_ 113 PRÍLOHY from dbo.Glasses glass0_ inner join dbo.Stringers stringers1_ on glass0_.GlassID=stringers1_.GlassID where glass0_.PartNo=@p0 and stringers1_.CreateTime>@p1',N'@p0 nvarchar(4000), @p1 datetime',@p0=N'9B.M2P09.102',@p1='2013-03-04 00:00:00'

NHibernate (LINQ) // Zdrojový kód: // NHibernate LINQ nepodporuje operáciu Distinct() pre anonymné typy (NHibernate bug NH-2380)

RavenDB // Zdrojový kód: // Kód je rovnaký ako v prípade predchádzajúceho testu (SelectPV3_Glass_Stringer)

5. SelectPV5_Glass_Stringer_Cell

ADO.NET // Zdrojový kód: string sqlString = @"SELECT g.ActualWatt, AVG(c.Grade) AS AvgGrade FROM NorthPV.dbo.Glasses g INNER JOIN NorthPV.dbo.Stringers s ON g.GlassID = s.GlassID INNER JOIN NorthPV.dbo.Cells c ON s.StringerID = c.StringerID GROUP BY g.GlassID, g.ActualWatt ORDER BY g.ActualWatt DESC" ; // SQL Server Profiler: SELECT g.ActualWatt, AVG(c.Grade) AS AvgGrade FROM NorthPV.dbo.Glasses g INNER JOIN NorthPV.dbo.Stringers s ON g.GlassID = s.GlassID INNER JOIN NorthPV.dbo.Cells c ON s.StringerID = c.StringerID GROUP BY g.GlassID, g.ActualWatt ORDER BY g.ActualWatt DESC

Entity Framework // Zdrojový kód: var outputs = from g in context.Glasses join s in context.Stringers on g.GlassID equals s.GlassID join c in context.Cells on s.StringerID equals c.StringerID group new { g, c } by new { g.GlassID, g.ActualWatt } into gg orderby gg.Key.ActualWatt descending select new { ActualWatt = gg.Key.ActualWatt, AvgGrade = gg.Average(x => x.c.Grade) }; // SQL Server Profiler: SELECT [Project1].[C2] AS [C1], [Project1].[ActualWatt] AS [ActualWatt], [Project1].[C1] AS [C2] FROM ( SELECT [GroupBy1].[A1] AS [C1], [GroupBy1].[K2] AS [ActualWatt], 1 AS [C2] FROM ( SELECT [Extent1].[GlassID] AS [K1], [Extent1].[ActualWatt] AS [K2], 114 PRÍLOHY AVG( CAST( CAST([Extent3].[Grade] AS int) AS float)) AS [A1] FROM [dbo].[Glasses] AS [Extent1] INNER JOIN [dbo].[Stringers] AS [Extent2] ON [Extent1].[GlassID] = [Extent2].[GlassID] INNER JOIN [dbo].[Cells] AS [Extent3] ON [Extent2].[StringerID] = [Extent3].[StringerID] GROUP BY [Extent1].[GlassID], [Extent1].[ActualWatt] ) AS [GroupBy1] ) AS [Project1] ORDER BY [Project1].[ActualWatt] DESC

LINQ to SQL // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: SELECT [t3].[ActualWatt], [t3].[value] AS [AvgGrade] FROM ( SELECT AVG(CONVERT(Int,[t2].[Grade])) AS [value], [t0].[ActualWatt] FROM [dbo].[Glasses] AS [t0] INNER JOIN [dbo].[Stringers] AS [t1] ON [t0].[GlassID] = [t1].[GlassID] INNER JOIN [dbo].[Cells] AS [t2] ON [t1].[StringerID] = [t2].[StringerID] GROUP BY [t0].[GlassID], [t0].[ActualWatt] ) AS [t3] ORDER BY [t3].[ActualWatt] DESC

LLBLGen Pro // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: SELECT [LPA_L1].[ActualWatt], [LPA_L1].[LPAV_] AS [AvgGrade] FROM ( SELECT [LPA_L3].[GlassID] AS [GlassId], [LPA_L3].[ActualWatt], AVG([LPA_L5].[Grade]) AS [LPAV_] FROM (( [NorthPV].[dbo].[Glasses] [LPA_L3] INNER JOIN [NorthPV].[dbo].[Stringers] [LPA_L4] ON [LPA_L3].[GlassID] = [LPA_L4].[GlassID]) INNER JOIN [NorthPV].[dbo].[Cells] [LPA_L5] ON [LPA_L4].[StringerID] = [LPA_L5].[StringerID]) GROUP BY [LPA_L3].[GlassID], [LPA_L3].[ActualWatt]) [LPA_L1] ORDER BY [LPA_L1].[ActualWatt] DESC

NHibernate (HQL) // Zdrojový kód: var query = session.CreateQuery( @"SELECT g.ActualWatt, AVG(c.Grade) as AvgGrade FROM Glass g JOIN g.Stringers s JOIN s.Cells c GROUP BY g.GlassID, g.ActualWatt ORDER BY g.ActualWatt DESC"); // SQL Server Profiler: select glass0_.ActualWatt as col_0_0_, AVG(cells2_.Grade) as col_1_0_ from dbo.Glasses glass0_ inner join dbo.Stringers stringers1_ on glass0_.GlassID=stringers1_.GlassID inner join dbo.Cells cells2_ on stringers1_.StringerID=cells2_.StringerID group by glass0_.GlassID , glass0_.ActualWatt order by glass0_.ActualWatt DESC

115 PRÍLOHY NHibernate (LINQ) // Zdrojový kód: // NHibernate LINQ nepodporuje operáciu GroupBy() podľa viacerých hodnôt

RavenDB // Zdrojový kód dopytu: var glasses = session.Query() .Select(x => new { ActualWatt = x.ActualWatt, AvgGrade = x.GradeAverage }).OrderByDescending(x => x.ActualWatt); // Zdrojový kód indexu: public class RavenGlasses_ByGlassStringerCellGrade : AbstractIndexCreationTask { public class ReduceResult { public string GlassID { get ; set ; } public double ? ActualWatt { get ; set ; } public short GradeCount { get ; set ; } public double GradeSum { get ; set ; } public double GradeAverage { get ; set ; } }

public RavenGlasses_ByGlassStringerCellGrade() { Map = glasses => from glass in glasses from stringer in glass.RavenStringers from cell in stringer.RavenCells select new { GlassID = glass.GlassID, ActualWatt = glass.ActualWatt, GradeCount = 1, GradeSum = ( double )cell.Grade, GradeAverage = 0 };

Reduce = results => results .GroupBy(x => new { x.GlassID, x.ActualWatt }) .Select(g => new { GlassID = g.Key.GlassID, ActualWatt = g.Key.ActualWatt, GradeCount = g.Sum(x => x.GradeCount), GradeSum = g.Sum(x => x.GradeSum) }) .Select(x => new { x.GlassID, x.ActualWatt, x.GradeCount, x.GradeSum, GradeAverage = x.GradeSum / x.GradeCount }); } } // Index na serveri: // Map docs.RavenGlasses .SelectMany(glass => glass.RavenStringers, (glass, stringer) => new { glass = glass, stringer = stringer }) 116 PRÍLOHY .SelectMany(this0 => this0.stringer.RavenCells, (this0, cell) => new { GlassID = this0.glass.GlassID, ActualWatt = this0.glass.ActualWatt, GradeCount = 1, GradeSum = ((double) cell.Grade), GradeAverage = 0 }) // Reduce results.GroupBy(x => new { GlassID = x.GlassID, ActualWatt = ((double ? ) x.ActualWatt) }).Select(g => new { GlassID = g.Key.GlassID, ActualWatt = g.Key.ActualWatt, GradeCount = Enumerable.Sum(g, x => ((int) x.GradeCount)), GradeSum = Enumerable.Sum(g, x => ((double)((double) x.GradeSum))) }) .Select(x => new { GlassID = x.GlassID, ActualWatt = ((double ? ) x.ActualWatt), GradeCount = x.GradeCount, GradeSum = ((double) x.GradeSum), GradeAverage = ((double) x.GradeSum) / ((double) x.GradeCount) })

6. SelectNW1

ADO.NET // Zdrojový kód: string sqlString = @"SELECT TOP 10 Products.ProductName AS TenMostExpensiveProducts, Products.UnitPrice FROM NorthPV.dbo.Products ORDER BY Products.UnitPrice DESC" ; // SQL Server Profiler: SELECT TOP 10 Products.ProductName AS TenMostExpensiveProducts, Products.UnitPrice FROM NorthPV.dbo.Products ORDER BY Products.UnitPrice DESC

Entity Framework // Zdrojový kód: var products = context.Products .OrderByDescending(x => x.UnitPrice) .Select(x => new { TenMostExpensiveProducts = x.ProductName, UnitPrice = x.UnitPrice }).Take(10); // SQL Server Profiler: SELECT TOP (10) [Project1].[C1] AS [C1], [Project1].[ProductName] AS [ProductName], [Project1].[UnitPrice] AS [UnitPrice] FROM ( SELECT [Extent1].[ProductName] AS [ProductName], [Extent1].[UnitPrice] AS [UnitPrice], 1 AS [C1] FROM [dbo].[Products] AS [Extent1] ) AS [Project1] ORDER BY [Project1].[UnitPrice] DESC

LINQ to SQL // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku 117 PRÍLOHY // SQL Server Profiler: SELECT TOP (10) [t0].[ProductName] AS [TenMostExpensiveProducts], [t0].[UnitPrice] FROM [dbo].[Products] AS [t0] ORDER BY [t0].[UnitPrice] DESC

LLBLGen Pro // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: exec sp_executesql N'SELECT TOP(@p2) [LPLA_1].[ProductName] AS [TenMostExpensiveProducts], [LPLA_1].[UnitPrice] FROM [NorthPV].[dbo].[Products] [LPLA_1] ORDER BY [LPLA_1].[UnitPrice] DESC',N'@p2 bigint',@p2=10

NHibernate (HQL) // Zdrojový kód: var query = session.CreateQuery (@"SELECT p.ProductName, p.UnitPrice FROM Product p ORDER BY p.UnitPrice desc" ); query.SetMaxResults(10); // SQL Server Profiler: exec sp_executesql N'select TOP (@p0) product0_.ProductName as col_0_0_, product0_.UnitPrice as col_1_0_ from dbo.Products product0_ order by product0_.UnitPrice desc',N'@p0 int',@p0=10

NHibernate (LINQ) // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: // Vygenerovaný SQL dopyt je rovnaký ako v prípade NHibernate HQL

RavenDB // Zdrojový kód dopytu: var products = session.Query< RavenCustomers_ByUnitPriceProduct .ReduceResult , RavenCustomers_ByUnitPriceProduct >() .Select(p => p) .Take(10) .OrderByDescending(p => p.UnitPrice); // Zdrojový kód indexu: public class RavenCustomers_ByUnitPriceProduct : AbstractIndexCreationTask { public class ReduceResult { public string TenMostExpensiveProducts { get ; set ; } public short UnitPrice { get ; set ; } }

public RavenCustomers_ByUnitPriceProduct() { Map = customers => from customer in customers from order in customer.RavenOrders from orderDetail in order.RavenOrderDetails from product in orderDetail.RavenProducts select new { TenMostExpensiveProducts = product.ProductName, UnitPrice = ( short )product.UnitPrice }; 118 PRÍLOHY Reduce = results => results .GroupBy(x => new { x.TenMostExpensiveProducts, x.UnitPrice }) .Select(g => new { TenMostExpensiveProducts = g.Key.TenMostExpensiveProducts, UnitPrice = g.Key.UnitPrice });

Sort(x => x.UnitPrice, Raven.Abstractions.Indexing.SortOptions.Short); } } // Index na serveri: // Map docs.RavenCustomers .SelectMany(customer => customer.RavenOrders, (customer, order) => new { customer = customer, order = order }) .SelectMany(this0 => this0.order.RavenOrderDetails, (this0,orderDetail) => new { this0 = this0, orderDetail = orderDetail }) .SelectMany(this1 => this1.orderDetail.RavenProducts, (this1, product) => new { TenMostExpensiveProducts = product.ProductName, UnitPrice = ((short)((decimal ? ) product.UnitPrice)) }) // Reduce results.GroupBy(x => new { TenMostExpensiveProducts = x.TenMostExpensiveProducts, UnitPrice = x.UnitPrice }) .Select(g => new { TenMostExpensiveProducts = g.Key.TenMostExpensiveProducts, UnitPrice = g.Key.UnitPrice })

7. SelectNW2_Procedure

ADO.NET // Zdrojový kód: string sqlString = @"Ten Most Expensive Products"; // SQL Server Profiler: exec Ten Most Expensive Products

Entity Framework // Zdrojový kód: var products = context.Ten_Most_Expensive_Products();

// SQL Server Profiler: exec [dbo].[Ten Most Expensive Products]

LINQ to SQL // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: declare @p3 int set @p3=0 119 PRÍLOHY exec sp_executesql N'EXEC @RETURN_VALUE = [dbo].[Ten Most Expensive Products]', N'@RETURN_VALUE int output',@RETURN_VALUE=@p3 output select @p3

LLBLGen Pro // Zdrojový kód: var reader = adapter.FetchDataReader( RetrievalProcedures . GetTenMostExpensiveProductsCallAsQuery(), CommandBehavior .CloseConnection); // SQL Server Profiler: exec [NorthPV].[dbo].[Ten Most Expensive Products]

NHibernate (HQL) // Zdrojový kód: var products = session.GetNamedQuery( "TenMostExpensiveProduct" ); // SQL Server Profiler: exec dbo.[Ten Most Expensive Products]

NHibernate (LINQ) // Zdrojový kód: // NHibernate LINQ nepodporuje volanie databázových procedúr

RavenDB // Zdrojový kód dopytu: // RavenDB nepodporuje volanie databázových procedúr

8. SelectNW3_CustomerProductQuantity

ADO.NET // Zdrojový kód: string sqlString = @"SELECT c.CompanyName, p.ProductName, sum(od.Quantity) as SumProduct FROM NorthPV.dbo.Customers c INNER JOIN NorthPV.dbo.Orders o ON c.CustomerID = o.CustomerID INNER JOIN NorthPV.dbo.[Order Details] od ON o.OrderID = od.OrderID INNER JOIN NorthPv.dbo.Products p ON od.ProductID = p.ProductID GROUP BY c.CompanyName, p.ProductName ORDER BY c.CompanyName, p.ProductName" ;

// SQL Server Profiler: SELECT c.CompanyName, p.ProductName, sum(od.Quantity) as SumProduct FROM NorthPV.dbo.Customers c INNER JOIN NorthPV.dbo.Orders o ON c.CustomerID = o.CustomerID INNER JOIN NorthPV.dbo.[Order Details] od ON o.OrderID = od.OrderID INNER JOIN NorthPv.dbo.Products p ON od.ProductID = p.ProductID GROUP BY c.CompanyName, p.ProductName ORDER BY c.CompanyName, p.ProductName

Entity Framework // Zdrojový kód: var products = from c in context.Customers join o in context.Orders on c.CustomerID equals o.CustomerID join od in context.Order_Details on o.OrderID equals od.OrderID join p in context.Products on od.ProductID equals p.ProductID group od by new { c.CompanyName, p.ProductName } into gg 120 PRÍLOHY orderby gg.Key.CompanyName, gg.Key.ProductName ascending select new { CompanyName = gg.Key.CompanyName, ProductName = gg.Key.ProductName, SumProduct = gg.Sum(x => x.Quantity) }; // SQL Server Profiler: SELECT [Project1].[C2] AS [C1], [Project1].[CompanyName] AS [CompanyName], [Project1].[ProductName] AS [ProductName], [Project1].[C1] AS [C2] FROM ( SELECT [GroupBy1].[A1] AS [C1],GroupBy1].[K1] AS [CompanyName], [GroupBy1].[K2] AS [ProductName], 1 AS [C2] FROM ( SELECT [Extent1].[CompanyName] AS [K1], [Extent4].[ProductName] AS [K2], SUM( CAST( [Extent3].[Quantity] AS int)) AS [A1] FROM [dbo].[Customers] AS [Extent1] INNER JOIN [dbo].[Orders] AS [Extent2] ON [Extent1].[CustomerID] = [Extent2].[CustomerID] INNER JOIN [dbo].[Order Details] AS [Extent3] ON [Extent2].[OrderID] = [Extent3].[OrderID] INNER JOIN [dbo].[Products] AS [Extent4] ON [Extent3].[ProductID] = [Extent4].[ProductID] GROUP BY [Extent1].[CompanyName], [Extent4].[ProductName] ) AS [GroupBy1] ) AS [Project1] ORDER BY [Project1].[CompanyName] ASC, [Project1].[ProductName] ASC

LINQ to SQL // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: SELECT [t4].[CompanyName], [t4].[ProductName], [t4].[value] AS [SumProduct] FROM ( SELECT SUM(CONVERT(Int,[t2].[Quantity])) AS [value], [t0].[CompanyName], [t3].[ProductName] FROM [dbo].[Customers] AS [t0] INNER JOIN [dbo].[Orders] AS [t1] ON [t0].[CustomerID] = [t1].[CustomerID] INNER JOIN [dbo].[Order Details] AS [t2] ON [t1].[OrderID] = [t2].[OrderID] INNER JOIN [dbo].[Products] AS [t3] ON [t2].[ProductID] = [t3].[ProductID] GROUP BY [t0].[CompanyName], [t3].[ProductName] ) AS [t4] ORDER BY [t4].[CompanyName], [t4].[ProductName]

LLBLGen Pro // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: SELECT [LPA_L1].[CompanyName], [LPA_L1].[ProductName], [LPA_L1].[LPAV_] AS [SumProduct] FROM (SELECT [LPA_L3].[CompanyName], [LPA_L6].[ProductName], SUM([LPA_L5].[Quantity]) AS [LPAV_] FROM ((( [NorthPV].[dbo].[Customers] [LPA_L3] INNER JOIN [NorthPV].[dbo].[Orders] [LPA_L4] ON [LPA_L3].[CustomerID] = [LPA_L4].[CustomerID]) INNER JOIN [NorthPV].[dbo].[Order Details] [LPA_L5] ON [LPA_L4].[OrderID] = [LPA_L5].[OrderID]) INNER JOIN [NorthPV].[dbo].[Products] [LPA_L6] ON [LPA_L5].[ProductID] = [LPA_L6].[ProductID]) GROUP BY [LPA_L3].[CompanyName], [LPA_L6].[ProductName]) [LPA_L1] ORDER BY [LPA_L1].[CompanyName] ASC,[LPA_L1].[ProductName] ASC

121 PRÍLOHY NHibernate (HQL) // Zdrojový kód: var query = session .CreateQuery(@"SELECT c.CompanyName, p.ProductName, SUM(od.Quantity) FROM Customer c JOIN c.Orders o JOIN o.OrderDetails od JOIN od.Product p GROUP BY c.CompanyName, p.ProductName ORDER BY c.CompanyName, p.ProductName "); // SQL Server Profiler: select customer0_.CompanyName as col_0_0_, product3_.ProductName as col_1_0_, SUM(orderdetai2_.Quantity) as col_2_0_ from dbo.Customers customer0_ inner join dbo.Orders orders1_ on customer0_.CustomerID=orders1_.CustomerID inner join dbo.[Order Details] orderdetai2_ on orders1_.OrderID=orderdetai2_.OrderID inner join dbo.Products product3_ on orderdetai2_.ProductID=product3_.ProductID group by customer0_.CompanyName , product3_.ProductName order by customer0_.CompanyName, product3_.ProductName

NHibernate (LINQ) // Zdrojový kód: // NHibernate LINQ nepodporuje operáciu GroupBy() podľa viacero hodnôt

RavenDB // Zdrojový kód dopytu: var products = session .Query() .Select(p => p) .OrderBy(p => p.CompanyName) .ThenBy(p => p.ProductName); // Zdrojový kód indexu: public class RavenCustomers_ByCustomerSumProducts : AbstractIndexCreationTask { public class ReduceResult { public string CompanyName { get ; set ; } public string ProductName { get ; set ; } public int SumProduct { get ; set ; } }

public RavenCustomers_ByCustomerSumProducts() { Map = customers => from customer in customers from order in customer.RavenOrders from orderDetail in order.RavenOrderDetails from product in orderDetail.RavenProducts select new { CompanyName = customer.CompanyName, ProductName = product.ProductName, SumProduct = orderDetail.Quantity };

Reduce = results => results .GroupBy(x => new { x.CompanyName, x.ProductName }) .Select(g => new { 122 PRÍLOHY CompanyName = g.Key.CompanyName, ProductName = g.Key.ProductName, SumProduct = g.Sum(x => x.SumProduct) }); Sort(x => x.CompanyName, Raven.Abstractions.Indexing.SortOptions.String); Sort(x => x.ProductName, Raven.Abstractions.Indexing.SortOptions.String); } } // Index na serveri: // Map docs.RavenCustomers .SelectMany(customer => customer.RavenOrders, (customer, order) => new { customer = customer, order = order }) .SelectMany(this0 => this0.order.RavenOrderDetails,(this0, orderDetail) => new { this0 = this0, orderDetail = orderDetail }) .SelectMany(this1 => this1.orderDetail.RavenProducts,(this1, product) => new { CompanyName = this1.this0.customer.CompanyName, ProductName = product.ProductName, SumProduct = this1.orderDetail.Quantity }) // Reduce results.GroupBy(x => new { CompanyName = x.CompanyName, ProductName = x.ProductName }) .Select(g => new { CompanyName = g.Key.CompanyName, ProductName = g.Key.ProductName, SumProduct = Enumerable.Sum(g, x => ((int) x.SumProduct)) })

9. SelectNW4_Supplier

ADO.NET // Zdrojový kód: string sqlString = @"SELECT s.SupplierID, s.CompanyName, s.ContactName, s.ContactTitle, s.Address, s.City, s.Region, s.PostalCode, s.Country, s.Phone, s.Fax, s.HomePage FROM NorthPV.dbo.Suppliers s WHERE SupplierID = @SupplierID" ; // SQL Server Profiler: exec sp_executesql N'SELECT s.SupplierID, s.CompanyName, s.ContactName, s.ContactTitle, s.Address, s.City, s.Region, s.PostalCode, s.Country, s.Phone, s.Fax, s.HomePage FROM NorthPV.dbo.Suppliers s WHERE SupplierID = @SupplierID',N'@SupplierID int',@SupplierID=25

Entity Framework // Zdrojový kód: var supplier = ( from s in context.Suppliers where s.SupplierID == 25 select s).Single(); // SQL Server Profiler: SELECT TOP (2) [Extent1].[SupplierID] AS [SupplierID], [Extent1].[CompanyName] AS [CompanyName], [Extent1].[ContactName] AS [ContactName], [Extent1].[ContactTitle] AS [ContactTitle], [Extent1].[Address] AS [Address], [Extent1].[City] AS [City], [Extent1].[Region] AS [Region], 123 PRÍLOHY [Extent1].[PostalCode] AS [PostalCode], [Extent1].[Country] AS [Country], [Extent1].[Phone] AS [Phone], [Extent1].[Fax] AS [Fax], [Extent1].[HomePage] AS [HomePage] FROM [dbo].[Suppliers] AS [Extent1] WHERE 25 = [Extent1].[SupplierID]

LINQ to SQL // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: exec sp_executesql N'SELECT [t0].[SupplierID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax], [t0].[HomePage] FROM [dbo].[Suppliers] AS [t0] WHERE [t0].[SupplierID] = @p0',N'@p0 int',@p0=25

LLBLGen Pro // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku

// SQL Server Profiler: exec sp_executesql N'SELECT [LPA_L1].[Address], [LPA_L1].[City], [LPA_L1].[CompanyName], [LPA_L1].[ContactName], [LPA_L1].[ContactTitle], [LPA_L1].[Country], [LPA_L1].[Fax], [LPA_L1].[HomePage], [LPA_L1].[Phone], [LPA_L1].[PostalCode], [LPA_L1].[Region], [LPA_L1].[SupplierID] AS [SupplierId] FROM [NorthPV].[dbo].[Suppliers] [LPA_L1] WHERE ( ( ( [LPA_L1].[SupplierID] = @p1)))',N'@p1 int',@p1=25

NHibernate (HQL) // Zdrojový kód: var query = session.CreateQuery( @"SELECT s FROM Supplier s WHERE s.SupplierID = 25"); // SQL Server Profiler: select supplier0_.SupplierID as SupplierID80_, supplier0_.CompanyName as CompanyN2_80_, supplier0_.ContactName as ContactN3_80_, supplier0_.ContactTitle as ContactT4_80_, supplier0_.Address as Address80_, supplier0_.City as City80_, supplier0_.Region as Region80_, supplier0_.PostalCode as PostalCode80_, supplier0_.Country as Country80_, supplier0_.Phone as Phone80_, supplier0_.Fax as Fax80_, supplier0_.HomePage as HomePage80_ from dbo.Suppliers supplier0_ where supplier0_.SupplierID=25

NHibernate (LINQ) // Zdrojový kód: var supplier = session.Query< Supplier >() .Where(s => s.SupplierID == 25) .Select(s => s).Single(); // SQL Server Profiler: exec sp_executesql N'select supplier0_.SupplierID as SupplierID98_, supplier0_.CompanyName as CompanyN2_98_, supplier0_.ContactName as ContactN3_98_, supplier0_.ContactTitle as ContactT4_98_, supplier0_.Address as Address98_, 124 PRÍLOHY supplier0_.City as City98_, supplier0_.Region as Region98_, supplier0_.PostalCode as PostalCode98_, supplier0_.Country as Country98_, supplier0_.Phone as Phone98_, supplier0_.Fax as Fax98_, supplier0_.HomePage as HomePage98_ from dbo.Suppliers supplier0_ where supplier0_.SupplierID=@p0',N'@p0 int',@p0=25

RavenDB // Zdrojový kód dopytu: var supplier = session.Query() .First(s => s.SupplierID == 25); // Zdrojový kód indexu: public class RavenSuppliers_BySupplierId : AbstractIndexCreationTask { public RavenSuppliers_BySupplierId() { Map = suppliers => from supplier in suppliers select new { supplier.SupplierID }; } } // Index na serveri: // Map docs.RavenSuppliers.Select(supplier => new { SupplierID = supplier.SupplierID })

10. InsertNW1

ADO.NET // Zdrojový kód: string sqlString = @"INSERT INTO NorthPV.dbo.Shippers (CompanyName, Phone) VALUES (@CompanyName, @Phone)"; // SQL Server Profiler: exec sp_executesql N'INSERT INTO NorthPV.dbo.Shippers (CompanyName, Phone) VALUES (@CompanyName, @Phone)',N'@CompanyName nvarchar(16), @Phone nvarchar(14)',@CompanyName=N'ADO Company Name',@Phone=N'(123) 456-7890'

Entity Framework // Zdrojový kód: var shipper = new Shipper { CompanyName = "EF Company Name" , Phone = "(123) 456-7890" }; context.Shippers.Add(shipper); // SQL Server Profiler: exec sp_executesql N'insert [dbo].[Shippers]([CompanyName], [Phone]) values (@0, @1) select [ShipperID] from [dbo].[Shippers] where @@ROWCOUNT > 0 and [ShipperID] = scope_identity()',N'@0 nvarchar(40), @1 nvarchar(24)',@0=N'EF Company Name',@1=N'(123) 456-7890'

LINQ to SQL // Zdrojový kód: var shipper = new Shipper { CompanyName = "L2S Company Name" , Phone = "(123) 456-7890" }; 125 PRÍLOHY linqDataContext.Shippers.InsertOnSubmit(shipper); // SQL Server Profiler: exec sp_executesql N'INSERT INTO [dbo].[Shippers]([CompanyName], [Phone]) VALUES (@p0, @p1) SELECT CONVERT(Int,SCOPE_IDENTITY()) AS [value]',N'@p0 nvarchar(4000), @p1 nvarchar(4000)',@p0=N'L2S Company Name',@p1=N'(132) 456-7890'

LLBLGen Pro // Zdrojový kód: ShipperEntity shipper = new ShipperEntity { CompanyName = "LLBL4 Company Name" , Phone = "(123) 456-7890" }; adapter.SaveEntity(shipper); // SQL Server Profiler: declare @p5 int set @p5=109889 exec sp_executesql N'INSERT INTO [NorthPV].[dbo].[Shippers] ([CompanyName], [Phone]) VALUES (@p1, @p2) ;SELECT @p3=SCOPE_IDENTITY()',N'@p1 nvarchar(40), @p2 nvarchar(24),@p3 int output',@p1=N'LLBL4 Company Name', @p2=N'(123) 456-7890',@p3=@p5 output select @p5

NHibernate (HQL) // Zdrojový kód: // NHibernate HQL nepodporuje vytváranie nových entít

NHibernate (LINQ) // Zdrojový kód: var shipper = new Shipper () { CompanyName = "NHHQL Company Name" , Phone = "(132) 456-7890" }; session.Save(shipper); // SQL Server Profiler: exec sp_executesql N'INSERT INTO dbo.Shippers (CompanyName, Phone) VALUES (@p0, @p1); select SCOPE_IDENTITY()',N'@p0 nvarchar(4000),@p1 nvarchar(4000)',@p0=N'NHHQL Company Name',@p1=N'(132) 456-7890'

RavenDB // Zdrojový kód: var shipper = new RavenShipper { CompanyName = "R Company Name" , Phone = "(123) 456-7890" };

11. InsertNW2 // Tento test sa od prechádzajúceho (InsertNW1) líši vkladaním viacerých hodnôt // do inej databázovej tabuľky

12. InsertNW3TransactionCommit // Tento test sa od prechádzajúceho (InsertNW1) líši vkladaním viacerých hodnôt // do inej databázovej tabuľky v potvrdenej transakcii

13. InsertNW4TransactionRollback // Tento test sa od prechádzajúceho (InsertNW1) líši vkladaním viacerých hodnôt // do inej databázovej tabuľky v zrušenej transakcii 126 PRÍLOHY 14. UpdatePV1

ADO.NET // Zdrojový kód: string sqlString = @"UPDATE NorthPV.dbo.Customers SET Country = @Country WHERE CustomerID = @CustomerID" ; // SQL Server Profiler: exec sp_executesql N'UPDATE NorthPV.dbo.Customers SET Country = @Country WHERE CustomerID = @CustomerID', N'@CustomerID nvarchar(5),@Country nvarchar(11)',@CustomerID=N'BLAUS', @Country=N'ADO Country'

Entity Framework // Zdrojový kód: var customer = context.Customers .First(c => c.CustomerID == "BLAUS" ); customer.Country = "EF Country" ; context.SaveChanges(); // SQL Server Profiler: exec sp_executesql N'update [dbo].[Customers] set [Country] = @0 where ([CustomerID] = @1)',N'@0 nvarchar(15),@1 nchar(5)',@0=N'EF Country',@1=N'BLAUS'

LINQ to SQL // Zdrojový kód: var customer = linqDataContext.Customers .First(c => c.CustomerID == "BLAUS" ); customer.Country = "L2S Country" ; linqDataContext.SubmitChanges(); // SQL Server Profiler: exec sp_executesql N'UPDATE [dbo].[Customers] SET [Country] = @p10 WHERE ([CustomerID] = @p0) AND ([CompanyName] = @p1) AND ([ContactName] = @p2) AND ([ContactTitle] = @p3) AND ([Address] = @p4) AND ([City] = @p5) AND ([Region] IS NULL) AND ([PostalCode] = @p6) AND ([Country] = @p7) AND ([Phone] = @p8) AND ([Fax] = @p9)', N'@p0 nchar(5),@p1 nvarchar(4000),@p2 nvarchar(4000),@p3 nvarchar(4000), @p4 nvarchar(4000),@p5 nvarchar(4000),@p6 nvarchar(4000),@p7 nvarchar(4000), @p8 nvarchar(4000),@p9 nvarchar(4000),@p10 nvarchar(4000)', @p0=N'BLAUS', @p1=N'Blauer See Delikatessen',@p2=N'Hanna Moos', @p3=N'Sales Representative', @p4=N'Forsterstr. 57',@p5=N'LLBL35 City',@p6=N'68306',@p7=N'EF Country', @p8=N'0621-08460',@p9=N'0621-08924',@p10=N'L2S Country'

LLBLGen Pro // Zdrojový kód: var customer = ( from c in metaData.Customer where c.CustomerId == "BLAUS" select c).Single(); customer.Country = "LLBL4 Country" ; adapter.SaveEntity(customer); // SQL Server Profiler: exec sp_executesql 127 PRÍLOHY N'UPDATE [NorthPV].[dbo].[Customers] SET [Country]=@p1 WHERE ( [NorthPV].[dbo].[Customers].[CustomerID] = @p2)', N'@p1 nvarchar(15),@p2 nchar(5)',@p1=N'LLBL4 Country',@p2=N'BLAUS'

NHibernate (HQL) // Zdrojový kód: var query = session.CreateQuery( @"UPDATE Customer c SET Country = 'NHHQL Country' WHERE c.CustomerID = 'BLAUS'" ); query.ExecuteUpdate(); // SQL Server Profiler: update dbo.Customers set Country='NHHQL Country' where CustomerID='BLAUS'

NHibernate (LINQ) // Zdrojový kód: var customer = (session.Query< Customer >() .Where(c => c.CustomerID == "BLAUS" ) .Select(c => c)).Single(); customer.Country = "NHLINQ Country" ; // SQL Server Profiler: exec sp_executesql N'UPDATE dbo.Customers SET CompanyName = @p0, ContactName = @p1, ContactTitle = @p2, Address = @p3, City = @p4, Region = @p5, PostalCode = @p6, Country = @p7, Phone = @p8, Fax = @p9 WHERE CustomerID = @p10',N'@p0 nvarchar(4000),@p1 nvarchar(4000),@p2 nvarchar(4000), @p3 nvarchar(4000),@p4 nvarchar(4000),@p5 nvarchar(4000), @p6 nvarchar(4000),@p7 nvarchar(4000),@p8 nvarchar(4000), @p9 nvarchar(4000),@p10 nvarchar(4000)', @p0=N'Blauer See Delikatessen',@p1=N'Hanna Moos', @p2=N'Sales Representative',@p3=N'Forsterstr. 57', @p4=N'LLBL35 City',@p5=NULL,@p6=N'68306',@p7=N'NHLINQ Country', @p8=N'0621-08460',@p9=N'0621-08924',@p10=N'BLAUS'

RavenDB // Zdrojový kód: var customer = session.Query() .First(c => c.CustomerID == "BLAUS" ); customer.Country = "R Country" ; session.SaveChanges();

15. UpdatePV2

ADO.NET // Zdrojový kód: string sqlString = @"UPDATE NorthPV.dbo.Customers SET City = @City"; // SQL Server Profiler: exec sp_executesql N'UPDATE NorthPV.dbo.Customers SET City = @City',N'@City nvarchar(8)',@City=N'ADO City'

128 PRÍLOHY Entity Framework // Zdrojový kód: foreach (var customer in context.Customers) { customer.City = "EF City" ; } context.SaveChanges(); // SQL Server Profiler: // Insert pre každý objekt Customer exec sp_executesql N'update [dbo].[Customers] set [City] = @0 where ([CustomerID] = @1) ',N'@0 nvarchar(15),@1 nchar(5)',@0=N'EF City',@1=N'ALFKI'

LINQ to SQL // Zdrojový kód: // LINQ výraz je rovnaký ako v prípade Entity Frameworku SQL Server Profiler

// SQL Server Profiler: // Insert pre každý objekt Customer exec sp_executesql N'UPDATE [dbo].[Customers] SET [City] = @p10 WHERE ([CustomerID] = @p0) AND ([CompanyName] = @p1) AND ([ContactName] = @p2) AND ([ContactTitle] = @p3) AND ([Address] = @p4) AND ([City] = @p5) AND ([Region] IS NULL) AND ([PostalCode] = @p6) AND ([Country] = @p7) AND ([Phone] = @p8) AND ([Fax] = @p9)',N'@p0 nchar(5),@p1 nvarchar(4000), @p2 nvarchar(4000),@p3 nvarchar(4000),@p4 nvarchar(4000),@p5 nvarchar(4000), @p6 nvarchar(4000),@p7 nvarchar(4000),@p8 nvarchar(4000),@p9 nvarchar(4000), @p10 nvarchar(4000)',@p0=N'ALFKI',@p1=N'Alfreds Futterkiste',@p2=N'Maria Anders', @p3=N'Sales Representative',@p4=N'Obere Str. 57',@p5=N'EF City',@p6=N'12209', @p7=N'Germany',@p8=N'030-0074321',@p9=N'030-0076545',@p10=N'L2S City'

LLBLGen Pro // Zdrojový kód: foreach (var customer in metaData.Customer) { customer.City = "LLBL4 City" ; adapter.SaveEntity(customer); } // SQL Server Profiler: // Insert pre každý objekt Customer exec sp_executesql N'UPDATE [NorthPV].[dbo].[Customers] SET [City]=@p1 WHERE ( [NorthPV].[dbo].[Customers].[CustomerID] = @p2)',N'@p1 nvarchar(15), @p2 nchar(5)',@p1=N'LLBL4 City',@p2=N'ALFKI'

NHibernate (HQL) // Zdrojový kód: var query = session.CreateQuery( @"UPDATE Customer c SET City = 'NHHQL City' WHERE c.CustomerID = 'BLAUS'" ); query.ExecuteUpdate(); // SQL Server Profiler: update dbo.Customers set City='NHHQL City' where CustomerID='BLAUS'

129 PRÍLOHY NHibernate (LINQ) // Zdrojový kód: foreach (var cus in session.Query< Customer >()) { cus.City = "NHLINQ City" ; session.Update(cus); } session.Flush(); // SQL Server Profiler: exec sp_executesql N'UPDATE dbo.Customers SET CompanyName = @p0, ContactName = @p1, ContactTitle = @p2, Address = @p3, City = @p4, Region = @p5, PostalCode = @p6, Country = @p7, Phone = @p8, Fax = @p9 WHERE CustomerID = @p10',N'@p0 nvarchar(4000),@p1 nvarchar(4000),@p2 nvarchar(4000), @p3 nvarchar(4000),@p4 nvarchar(4000),@p5 nvarchar(4000),@p6 nvarchar(4000), @p7 nvarchar(4000),@p8 nvarchar(4000),@p9 nvarchar(4000),@p10 nvarchar(4000)', @p0=N'Alfreds Futterkiste',@p1=N'Maria Anders',@p2=N'Sales Representative', @p3=N'Obere Str. 57',@p4=N'NHLINQ City',@p5=NULL,@p6=N'12209', @p7=N'Germany', @p8=N'030-0074321',@p9=N'030-0076545',@p10=N'ALFKI'

RavenDB // Zdrojový kód: foreach (var customer in customers) { customer.City = "R City" ; } session.SaveChanges();

16. DataContext1 // Tento test spočíva vo vytvorení prázdneho DataContextu / Session

17. Threads1 // Tento test vytvára entitu Shipper (viď test InsertNW1) v jednom vytvorenom vlákne

18. Threads5 // Tento test vytvára entity Shipper v piatich vláknach aplikácie naraz

19. Threads10 // Tento test vytvára entity Shipper v desiatich vláknach aplikácie naraz

20. Threads15 // Tento test vytvára entity Shipper v pätnástich vláknach aplikácie naraz

21. Library cold load // Tento test spočíva vo vykonaní prvého testu (SelectPV1_Glass) pri studenom štarte // aplikácie bez WarmUp iterácie, kde bol monitorovaný prvý čas potrebný na // inicializáciu ORM nástroja.

130 PRÍLOHY Príloha C: Elektronické prílohy

V elektronickej prílohe na DVD sa nachádzajú zdrojové kódy celého riešenia, dátové a transakčné súbory oboch databáz serveru SQL Server a spustiteľná databáza RavenDB. Databázy obsahujú dáta v rozsahu podľa tabuľky 8.1, teda pred pridávaním testovacích záznamov. Databáza aplikácie ProteinLite obsahuje ukážkových sto záznamov. Pre spustenie oboch aplikácií je nutné zmeniť názov serveru v konfiguračných súboroch, stačí použiť funkciu na vyhľadávanie a prepísanie názvu „SILENT-PC“ na nový. V poslednom rade sa na DVD nachádzajú PDF súbory tejto práce a diagramu databáz.

Príloha D: Namerané výsledky testov

Na nasledujúcich stranách sa nachádzajú všetky namerané výsledky z testovania. Tabuľky 10.1 a 10.2 obsahujú výsledky testov z aplikácie ORM Test, tabuľky 10.3, 10.4 a 10.5 obsahujú časy zápisov a načítavania záznamov z aplikácie ProteinLite.

131 PRÍLOHY

kompilované LINQ to ADO.NET EF 5.0 LINQ to SQL Výsledky SQL ORM Test Min Priemer Max Min Priemer Max Min Priemer Min Priemer Max (ms) Max (ms) (ms) (ms) (ms) (ms) (ms) (ms) (ms) (ms) (ms) (ms) SelectPV1 2,15 2,24 2,8 3,52 3,75 4,82 6,17 6,45 6,78 2,36 2,44 2,82 SelectPV2 1,97 2,12 2,95 3,24 3,45 3,93 2,61 2,7 3,44 - - - SelectPV3 5,35 5,53 6,62 10,91 11,09 11,75 11,65 11,76 12,61 5,69 5,58 7,74 SelectPV4 10,08 10,75 14,06 15,7 16,02 16,63 19,47 20,2 20,82 12,7 12,84 13,3 SelectPV5 92,38 95,19 112,2 102,43 106,87 118,68 115,13 118,2 132,41 97,03 98,84 111,19 SelectNW1 x10 2,98 3,16 5,29 13,25 13,93 24,3 9,43 10,39 18,8 5,5 5,79 10,82 SelectNW2 x10 3,28 3,37 6,01 10,07 10,83 20,01 5,72 6,14 8,11 - - - SelectNW3 8,24 8,38 12,91 11,57 12,01 12,92 13,69 15,04 18,75 9,23 9,48 10,25 SelectNW4 x10 6,23 6,96 12,28 11,58 12,05 21,58 10,02 10,58 11,04 5,88 6,12 9,49 InsertNW1 x10 2,31 2,86 6,06 18,92 20,00 27,42 7,55 8,51 14,45 - - - InsertNW2 2,48 2,82 4,09 11,49 12,28 20,63 8,08 8,56 9,56 - - - InsertNW3 2,99 3,14 4,77 9,34 9,81 10,86 11,16 11,66 12,92 - - - InsertNW4 3,3 3,51 4,92 9,35 9,97 11,52 11,21 11,8 13,16 - - - UpdatePV1 x10 2,27 2,85 7,54 11,29 12,34 14,44 8,2 8,73 12,37 - - - UpdatePV2 x10 3,92 4,68 8,99 31,32 33,57 34,91 11,33 12,02 13,84 - - - DataContext x50 0,04 0,07 0,34 0,20 0,32 1,71 1,21 1,28 2,04 - - - Threads1 0,56 0,7 2,66 2,16 2,68 4,37 2,32 2,47 4,04 - - - Threads5 0,87 1,68 2,92 4,99 5,93 8,33 6,09 6,83 9,61 - - - Threads10 1,69 2,11 4,48 9,89 11,31 14,93 11,38 13,37 15,71 - - - Threads15 2,57 3,25 6,55 15,44 16,07 18,97 17,69 19,84 23,44 - - - Library cold load 164 172 197 502,1 640 692,8 199,2 224,3 276 - - - Tabuľka 10.1: Prvá časť výsledkov ORM Test 132 PRÍLOHY

LLBLGen Pro 3.5 LLBLGen Pro 4.0 NHibernate (HQL) NHibernate (LINQ) RavenDB Výsledky ORM Test Min Priemer Max Min Priemer Max Min Priemer Max Min Priemer Max Min Priemer Max (ms) (ms) (ms) (ms) (ms) (ms) (ms) (ms) (ms) (ms) (ms) (ms) (ms) (ms) (ms) SelectPV1 4,09 4,51 6,49 4,01 4,21 6,28 3.7 3,27 7,72 4,18 4,38 5,37 17,7 19,9 25,18 SelectPV2 2,35 2,4 2,8 2,3 2,47 2,76 2,98 3,15 6,18 ------SelectPV3 8,2 8,51 9,44 8,17 8,58 9,33 6 6,17 9,43 7,13 7,25 7,97 20,01 21,46 23,23 SelectPV4 17,23 18,32 19,24 17,76 18,31 19,26 11,98 12,13 13,33 - - - 20,12 21,75 25,84 SelectPV5 100,2 102,67 123,26 99,93 102,34 119,42 95,23 97,74 117,53 - - - 199,1 201,72 203,47 SelectNW1 x10 19,1 23,23 38,87 20,56 27,23 36,6 4,75 5,22 11,87 7,1 7,59 9,14 18,61 21,73 35,15 SelectNW2 x10 4,33 4,52 7,1 4,21 4,46 6,79 4,33 5,14 7,5 ------SelectNW3 13,29 14,43 16,22 13,25 14,28 15,92 10,94 11,19 13,57 - - - 53,7 56,87 77,34 SelectNW4 x10 7,29 7,97 9,19 4,5 5,33 6,19 4,33 4,88 10,72 12,3 13,36 17,48 14,4 30,17 37,48 InsertNW1 x10 5,92 6,76 12,25 4,73 6,02 14,25 - - - 4,11 4,47 8,28 57,55 69,18 132,78 InsertNW2 5,07 5,7 6,72 5,54 5,91 7,96 - - - 3,99 4,23 5,03 80,01 128,07 191,74 InsertNW3 5,5 5,99 7,36 5,57 6,11 8,24 - - - 2,76 2,96 3,67 62,4 77,61 193,56 InsertNW4 5,62 6,12 6,7 4,47 6,24 8,47 - - - 2,58 2,75 3,63 51,5 56,96 102,98 UpdatePV1 x10 4,2 5,34 6,79 6,72 8,48 13,92 3,42 3,95 6,14 13,36 14,08 16,55 76,54 78,17 81,06 UpdatePV2 x10 3,74 4,98 6,69 4,11 4,93 8,77 3,45 3,93 6,37 38,6 40,27 44,1 12665 13179,8 13929 DataContext x50 0,13 0,16 1,15 0,15 0,17 0,97 2,7 2,98 6,8 - - - 0,38 0,73 3,71 Threads1 0,7 0,99 2,34 0,61 0,78 1,53 - - - 36,67 42,1 51,88 14,29 22,22 34,89 Threads5 1,44 1,87 3,09 1,49 1,87 3,24 - - - 131,11 163,3 273,14 82,57 131,43 178,87 Threads10 2,96 3,74 5,61 3,33 3,72 6,11 - - - 295,13 322,7 481,2 216,28 302,43 526,75 Threads15 4,44 5,41 7,91 4,81 5,07 10,77 - - - 436,2 595,01 965,2 376,52 496,83 725,27 Library cold load 837,7 854,7 976,4 778,1 859,3 881 769,3 792,8 811 898,4 915,3 965,9 712,1 730,15 780,6 Tabuľka 10.2: Druhá časť výsledkov ORM Test

133 PRÍLOHY

Bulk ADO.NET (10 File.Write ADO.NET (1 MB) ADO.NET (10 MB) Zápisovanie MB) záznamov Celkové Celkový Čas na Celkové Celkový Čas na Celkové Celkový Čas na Celkové Celkový Čas na dáta (kB) čas (ms) 1000 kB dáta (kB) čas (ms) 1000 kB dáta (kB) čas (ms) 1000 kB dáta (kB) čas (ms) 1000 kB 10 záznamov 14925 325,7 21,82 4050 437,8 108,1 23661 1832,8 77,46 4381 214,5 48,96 10 záznamov 13726 281,4 20,5 14497 1526 105,26 4733 294,1 62,14 5345 274,3 51,32 10 záznamov 4380 159,7 36,46 5382 510,7 94,89 14423 1076,4 74,63 23774 1641,1 69,03 100 záznamov 115046 3103,8 26,98 67483 8393 124,37 78387 5193,8 66,26 95901 7104,2 74,08 100 záznamov 96180 2092,9 21,76 85548 9362,3 109,44 124506 8936,1 71,77 75931 5624,1 74,07 100 záznamov 55558 1982,4 35,68 125232 13804,4 110,23 111893 7267 64,95 123918 9370,8 75,62 500 záznamov 554992 10921 19,68 434683 54042,1 124,33 415014 37757,7 90,98 517610 38936 75,22 500 záznamov 492060 11959,7 24,31 579402 79549,5 137,3 418450 37277,6 89,08 485290 36179,3 74,55 500 záznamov 437307 9749,8 22,3 434727 57178,7 131,53 496749 42983,5 86,53 476290 35012,2 73,51 1000 záznamov 898641 23834,6 26,52 944878 123949,7 131,18 1084285 100804,9 92,97 865226 72662,2 83,98 1000 záznamov 898193 23450,9 26,11 950524 129547,1 136,29 1033677 97870,5 94,68 944093 79948,6 84,68 1000 záznamov 929004 24577,6 26,46 978845 149780 153,02 984506 102358,1 103,97 940841 80115 85,15 5000 záznamov 4893228 171652 35,08 4936878 799699 161,98 5078830 485151,1 95,52 4785113 441437,1 92,25 5000 záznamov 4793990 170296,4 35,52 4636950 743201 160,28 4568270 396342,1 86,76 4666985 441024,7 94,5 5000 záznamov 489212 17224,6 35,21 4568722 713082,9 156,08 5303165 510157 96,2 5120123 468545,7 91,51 10000 záznamov 9653061 302610 31,35 9685192 1605982,1 165,82 9682202 914416 94,44 9186816 850839,5 92,62 10000 záznamov 8558058 298242 34,85 9378011 1571107 167,53 9253714 858085,4 92,73 9324540 858841,5 92,11 10000 záznamov 9766586 340541 34,87 9725480 1569451,5 161,38 9452251 849563,7 89,88 10101045 911213,1 90,21 Tabuľka 10.3: Prvá časť výsledkov zápisu ProteinLite

134 PRÍLOHY

RavenDB bulk Bulk EF (10MB) RavenDB documenty RavenDB prílohy Zápisovanie documenty záznamov Celkové Celkový Čas na Celkové Celkový Čas na Celkové Celkový Čas na Celkové Celkový Čas na dáta (kB) čas (ms) 1000 kB dáta (kB) čas (ms) 1000 kB dáta (kB) čas (ms) 1000 kB dáta (kB) čas (ms) 1000 kB 10 záznamov 4497 369,5 82,17 5312 1000,5 188,35 4360 419,8 96,28 3568 508,4 142,49 10 záznamov 4799 533,7 111,21 24051 5204,6 216,4 6005 714,2 118,93 4953 632,1 127,62 10 záznamov 5311 354,6 66,77 15372 2732,3 177,75 14248 1598,7 112,21 5101 716,7 140,5 100 záznamov 116300 10059,7 86,5 105452 21024,2 199,37 100635 17737 176,25 85323 12249,4 143,57 100 záznamov 117023 9759,9 83,4 95323 18687 196,04 102754 18127,4 176,42 114213 15851,3 138,79 100 záznamov 98454 8654,3 87,9 119439 23312,3 195,18 89229 16162 181,13 97554 13641,1 139,83 500 záznamov 515787 39346,1 76,28 475117 99680,8 209,8 548779 92610,8 168,76 458347 64985,7 141,78 500 záznamov 519604 40752 78,43 476920 102328,3 214,56 409835 67480 164,65 415427 58129,8 139,93 500 záznamov 502024 39874 79,43 489578 105523 215,54 489561 83602,8 170,77 428660 59367,7 138,5 1000 záznamov 978096 71909,7 73,52 1033397 222242,1 215,06 900801 162797,6 180,73 961731 133717,2 139,04 1000 záznamov 894548 70094 78,36 97541 20655,7 211,76 949410 165794 174,63 974541 134542,9 138,06 1000 záznamov 921561 69987 75,94 990562 208702,5 210,69 938441 169537,1 180,66 1024951 145621,4 142,08 5000 záznamov 4708208 375554 79,77 4705127 1031135,3 219,15 - - - 4675020 708610,1 151,57 5000 záznamov 4844869 382837,7 79,02 4996241 1055907,7 211,34 - - - 4687285 687584 146,69 5000 záznamov 4954478 395413,7 79,81 4782247 1054122,1 220,42 - - - 4987451 709551,9 142,27 10000 záznamov 10231104 798131,9 78,01 9449901 2071608,6 219,22 - - - 9076452 1296246,9 142,81 10000 záznamov 9784515 799544 81,72 9399292 2049549,5 218,05 - - - 9375558 1329023,1 141,75 10000 záznamov 9887112 831541,2 84,1 10247160 2258594,6 220,41 - - - 9422380 1350468,1 143,33 Tabuľka 10.4: Druhá časť výsledkov zápisu ProteinLite

135 PRÍLOHY

File.Read ADO.NET RavenDB prílohy Načítavanie záznamov Celkové Celkový Čas na Celkové Celkový Čas na Celkové Celkový Čas na dáta (kB) čas (ms) 1000 kB dáta (kB) čas (ms) 1000 kB dáta (kB) čas (ms) 1000 kB 10 záznamov 5744 7,8 1,36 4876 32,7 6,71 4896 284,2 58,05 10 záznamov 5740 6,6 1,15 24353 122 5,01 15252 863,5 56,62 10 záznamov 15622 16,5 1,06 14140 70,8 5,01 14235 711,6 49,99 100 záznamov 107093 124,7 1,16 114449 443,3 3,87 92268 4799,4 52,02 100 záznamov 105843 110,5 1,04 105689 401,9 3,8 89602 4366,8 48,74 100 záznamov 96191 98,1 1,02 99773 389 3,9 100958 4518,6 44,76 Tabuľka 10.5: Výsledky načítavania ProteinLite

136