Tento díl našeho blogu navazuje na porovnání základních vlastností ORM frameworků a věnuje se jejich dalším vlastnostem, které považujeme za důležité. Na závěr jsme shrnuli základní poznatky a uvádíme doporučení, kdy který framework použít.
Porovnání přístupu k vývoji
Při vývoji je potřeba udržovat jak entitní vrstvu, tak mapování a také databázové schéma. Následující tabulka shrnuje možnosti frameworků.
NHibernate | Entity Framework | |
Code first Přístup, kdy vývojář definuje objektový model a framework z něj umožní vygenerovat SQL objekty. Pro velké enterprise aplikace těžko použitelné, proto považujeme za okrajovou vlastnost. |
Není podporováno. | Je podporováno. |
Code migrations Jde o specifikování změn schématu databáze v C# kódu voláním metod typu AddColumn apod. Framework sám vygeneruje a popř. spustí změnové skripty. |
Podporováno v projektu Fluent Migrations | Je podporováno. |
DB first Z SQL schematu vygeneruje ORM vrstvu. Typický postup pro enterprise aplikace. |
Není přímo podporováno, existují nástroje třetích stran na vygenerování mapování a entit (myGeneration, NHibernate Mapping Generator). Namísto tohoto přístupu lze mapování a entity napsat ručně (viz níže). | Je podporováno. Pracnější, když názvy objektů, sloupců, atd. v DB neodpovídají C# CamelCase notaci (musí se ručně přepsat v designeru). |
Model first Mapování probíhá v modeleru v IDE, ten vygeneruje mapování, entity i databázové skripty. |
Není přímo podporováno, existují komerční nástroje (Mindscape NHibernate Designer, Devart NHibernate Designer) | Je podporováno. |
Mapping first Nejprve vzniká mapování, z něho se generuje změnový databázový skript i entity. |
Tento přístup dává smysl pouze u XML mapování NHibernate. Je podporováno pomocí interního nástroje hbm2ddl a projektu hbm2net. |
Pro EF není relevantní. |
Ruční přístup Udržování entit, mapování a databáze zvlášť, bez generování. Tento přístup má vyšší pracnost, ale velkou flexibilitu (vše je plně pod kontrolou, nestane se že generátor vygeneruje entitu jinak než chceme). |
Je podporováno. | Je podporováno. |
V této kapitole hodnotíme jako lepší EF, protože navíc umí CodeFirst, a také má vše potřebné integrováno ve Visual Studiu. To programátorovi zjednodušuje a zrychluje práci.
Intercepting
Pod pojmem intercepting rozumíme možnost odchytávání událostí daného ORM frameworku typu uložení/načtení/mazání/update entity s provedením vlastního kódu.
NHibernate umožňuje odchytávat mnoho událostí včetně těch zmíněných, a to pomocí staršího mechanismu Listeners nebo novějšího Events. Mechanismus Listeners jsme s úspěchem použili pro auditování operací nad Oracle databází (konkrétně mazání hodnot z podřízené kolekce).
EF přímo možnost odchycení těchto událostí nenabízí, ale jelikož je postaven na ADO.NET, tak je možné využít podporu ADO.NET k těmto účelům. Využití tohoto mechanizmu se může hodit během vývoje při ladění chyb, kde stejným způsobem můžeme v případě MS SQL použít profiler, standardně dodávaný v rámci SQL Management Studia. U jiných DB strojů ale tato možnost být nemusí, popř. k ní může být potřeba koupit speciální nástroj (např. pro Oracle). V produkčním provozu a zejm. u aplikací a databází s velkým provozem často kvůli negativnímu vlivu na výkon stejně využít nelze.
V oblasti interceptingu je NHibernate lepší.
Funkce pro zlepšení výkonu
NHibernate obsahuje několik zajímavých vlastností pro optimalizaci výkonu. Jednak jsou to generátory ID, kde jsou v nabídce možnosti pro optimalizaci počtu požadavků na nový identifikátor na server (detaily v článku NHibernate POID Generators revealed). Dále jsou to tzv.Futures, což je možnost seskupit více (i nesouvisejících) dotazů do jediného požadavku. A v neposlední řadě je to plugovatelná podpora application-wide cachování zvaná Second level cache. Mezi providery patří např. memchached, ASP.NET Web Cache, AppFabric Cache (dříve kódové jméno Velocity; nyní je potřeba externí provider) a další.
Tyto vlastnosti v EF nenajdeme, což může být silný argument ve prospěch NHibernate pro aplikace s velkým datovým provozem a velkým počtem současně pracujících uživatelů v případě, že s tím aplikační architektura nepočítala od začátku.
Další silné a slabé stránky frameworků
V této kapitole uvádíme některé zajímavé stránky každého z frameworků bez vzájemného srovnávání, které není vždy možné.
NHibernate je silný v mapování kolekcí, kde umožňuje detailně mapovat 1:N a M:N relace, množiny, key-value kolekce. Daní za flexibilitu je ale složitost konfigurace kolekcí v mapování. V EF takové možnosti nemáme, nicméně na druhou stranu to není nic zásadního a lze to obejít v .NET kódu s o málo větší pracností. NHibernate tak dává lepší možnosti pro definování kvalitního objektového modelu. Zde se při naší diskuzi objevil rozpor, jak velkou přidanou hodnotu tato vlastnost představuje. Zastánci EF tvrdí, že v praxi toto stejně málokdy využijeme, resp. že to nejsme zvyklí využívat buď vůbec, a nebo správně. Takže nás vlastně znatelně omezenější možnosti EF neomezují. A nebo ano?
EF podporuje task based pattern zavedený v .NET 4.5 (async/await), což NHibernate v dohledné době nabízet nebude. Opět jde ale o funkcionalitu, bez které se snadno obejdeme, zejm. u webových aplikací.
EF nepodporuje mapování SQL procedur, které mají v argumentech použity user defined table types. Zpřístupnit takovou proceduru pro EF tak musí programátor ručně psaným ADO.NET kódem, kde je toto podporováno. Na druhou stranu NHibernate toto řeší podobně komplikovaným přístupem.
Slabou stránkou EF je práce s SQL views. EF na ně neumožňuje namapovat vztahy dle cizích klíčů, a tedy v objektové reprezentaci u views nemáme k dispozici navigable properties. To v podstatě znemožňuje použití views ve složitějších konstrukcích. Joiny je v takovém případě potřeba napsat v LINQ ručně a převádět si získané objekty do kolekcí objektů, což je silně nepraktické. Toto může diskvalifikovat použití EF, je-li DB rozhraní na views postavené. V opačném případě nás ale nemusí vůbec zajímat.
Další slabinou EF jsou DML operace pomocí updateable views. Tedy situace, kdy potřebujeme nad SQL pohledy provádět INSERT, UPDATE, DELETE. Pro EF je potřeba pro DML operace vytvořit a namapovat SQL procedury, kdy pro každý změněný objekt (řádek databáze) je vždy zavolána procedura. To nejen komplikuje vývoj, ale především vylučuje použití EF v situacích, kdy předpokládáme zpracovávat desítky nebo více řádků najednou. Z výkonnostních důvodů pak není možné připustit, aby aplikace volala opakovaně během zpracování jednoho požadavku proceduru pro každý objekt. Lze použít workaround, kdy ruční změnou EDMX modelu přesvědčíme EF, že má pohled považovat za tabulku. Pokud ale kdykoli v budoucnu provedeme update modelu z databáze, tak musíme tento ruční zásah vždy opakovat. To nelze doporučit pro enterprise aplikace a velké vývojové týmy. Jednak to zpomalí práci a dále to bude znamenat komplikace při úpravě aplikace dejme tomu po několika letech provozu, kdy už v týmu budou jiní programátoři nebo původní na tuto specialitu zapomenou.
EF tedy v podstatě nelze použít v situaci, kdy bychom chtěli business logiku odstínit právě přes viewsa pomocí nich vytvořit aplikační rozhraní tak, aby aplikace vůbec nepřistupovala přímo do tabulek. Takový design může být vhodný právě pro velké datově orientované aplikace, kdy se z výkonnostních důvodů neubráníme zabudování business logiky do DB vrstvy. Tento problém jsme museli řešit při implementaci účetní aplikace pro automatické párování bankovních výpisů, kde šlo o databázi s tabulkami o velikostech desítek až stovek GB a poměrně složitou účetní logikou. Nakonec jsme použili EF a omezili využití views, jelikož se to ukázalo jako méně pracné, než implementace v NHibernate. Do budoucna to ale přináší o něco větší pracnost při změnách aplikační logiky, kdy bude nutné spolu s DB vrstvou upravit i samotnou .NET aplikaci. V případě tohoto projektu se však nepočítá s častými změnami aplikace, takže tento argument v neprospěch EF odpadl, a naopak převážily ostatní výhody.
Pokud tedy dopředu víme, že výše popsané vlastnosti SQL views nebudeme potřebovat, tak můžeme tuto slabinu při volbě frameworku ignorovat. V opačném případě naopak jasně vidíme, že použití EF nebude rozumné.
Další dotazovací mechanismy v NHibernate
NHibernate kromě LINQ provideru a HQL nabízí ještě dva další dotazovací mechanismy. Jednak je to Criteria API, staré API s komplikovanou syntaxí a bez statické kontroly při překladu (názvy properties jsou uváděny řetězcem). Od verze NHibernate 3.0 je zde mechanismus QueryOver, staticky typovaný, využívající lambda funkce. Je to silný nástroj, plně podporuje několikanásobné INNER a OUTER JOINy, stejně jako vracení pouze požadovaných sloupců místo celé entity. Není to LINQ provider, to však nemusí vadit, zápis dotazu je dobře čitelný.
Na druhou stranu, NHibernate bývá terčem kritiky za přílišné množství dotazovacích mechanismů, kdy není schopen kvalitně podporovat standardní LINQ, a místo toho přidává nové API (což je případ QueryOver).
Výhled do budoucna
Vývoj NHibernate se v poslední době zpomaluje. Udává se, že počet aktivních vývojářů se ustálil na pouhých dvou. Je to vidět např. v počtu commitů za poslední rok na Ohloh.net: NHibernate,Entity Framework. Integrace nových vlastností .NET frameworku do NHibernatu zaostává, např. podpora .NET 4 je nyní pouze v alfa verzi frameworku (4.0).
Entity framework je mladší, ale rychle se vyvíjí a získává funkce dříve dostupné pouze v NHibernate. Microsoft propaguje již několik let EF jako svoji primární technologii pro přístup k databázi v .NET , což potvrzuje i jeho poměrně rychlým vývojem. To dává jistotu, že bude ještě dlouhou dobu podporován a dále vyvíjen.
Databázová podpora
NHibernate podporuje MS SQL Server, Oracle, DB2, MySQL, SQLite, PostgreSQL a Firebird.
V případě EF je primární podpora pro MS SQL server, s ostatními DB stroji již není EF integrován na tak vysoké úrovni. Je to dáno také tím, že EF je navržen primárně pro MS SQL. Některé jeho specifické vlastnosti tak nemohou být z principu pro ostatní DB stroje implementovány a naopak jiné specifické vlastnosti jiných DB strojů nemohou být plně využity v EF. Je proto potřeba se připravit na drobné problémy, pokud použijete EF s jinou databází, než MS SQL (příkladem může být malý výkon stránkování pomocí Skip/Take v databázi Oracle). Na druhou stranu toto všechno je dobře zdokumentované výrobci daných providerů pro EF pro daný DB server a také je k dispozici spousta informací na Internetu.
V oblasti podpory jednotlivých databází má navrch NHibernate.
Podpora ve Visual Studiu
Další neméně důležitou výhodou EF je vestavěná podpora ve Visual Studiu, včetně grafického designeru. K dispozici je i mnoho volných third-party knihoven s rozšířeními EF. Pro NHibernate podpora ve Visual Studiu není, ale existují alespoň placené designery Mindscape NHibernate Designer, Devart NHibernate Designer.
Z důvodu vestavěného designeru v této kategorii vítězí Entity Framework.
Závěrečné zhodnocení
EF
Při použití vlastností podporovaných v EF je vývoj v tomto frameworku rychlejší v porovnání s NHibernate. Pro C# programátora vypadá EF vyspěleji, poměrně snadno se s ním pracuje, a má rychlou učící křivku. Entity Framework bychom vybrali určitě pro nové menší projekty. Pro EF mluví dále fakt, že se rychle vyvíjí a většinu slabin lze s určitým navýšením pracnosti úspěšně řešit, např. přímým použitím ADO.NET.
Na druhou stranu EF není v některých případech vhodný na práci s velkými daty a má řadu nedostatků. Většinu z nich lze řešit různými workaroundy, third-party knihovnami, atd. To už ale zase na druhou stranu jeho použití komplikuje, vytváří nároky na specifické vědomosti vývojářů a zvyšuje riziko při použití ve velkých enterprise projektech. Zde jsme opět mezi zastánci EF a NHibernate nenalezli jasnou shodu. Při diskuzi zaznělo, že o EF lze i na velkých projektech uvažovat v případě, kdy máme pod kontrolou také návrh fyzického DB modelu a jsme tedy schopni bez zásadních komplikací omezit výše popsané situace, se kterými si EF nedokáže rozumně poradit. Příklady z naší praxe toto potvrzují.
NHibernate
NHibernate je vyspělý a odladěný framework, dlouhou dobu používaný mnoha vývojáři. NHibernate doporučujeme v případě jiné databáze než MS SQL Server (v enterprise prostředí nemusí být možnost si providera databáze libovolně zvolit), protože má širší a více konzistentní podporu jiných databázových strojů. NHibernate je vhodné dále zvážit ve velkých projektech, kde je zásadní výkon a škálovatelnost. Pokud máme tým, který dobře zná NHibernate a víme, že vše co budeme pro projekt potřebovat je v NHibernate podporováno, tak se kloníme spíše k tomuto frameworku.
Hlavním rizikem NHibernate je však jeho podpora do budoucna, implementace funkcí z nových verzí .NET frameworku se výrazně zpomalila a snížil se počet vývojářů. Použití některých standardních vlastností je v NHibernate o něco pracnější než v EF, slabinou NHibernate je také dokumentace.