Dapper – Micro ORM Framework

Dapper je malý a jednoduchý ORM (objektově relační mapper) pro .NET, který má na svědomí tým vývojářů ze StackOwerflow. Na StackOwerflow je nasazen v produkčním prostředí, takže se vůbec nemusíte bát ho použít na Vašem projektu. Na rozdíl od jiných ORM farameworků se vyznačuje jednoduchostí a především rychlostí.

Výkon

Klíčovou vlastností Dapperu je rchlost. To je dáno tím, že pracuje nad čistým ADO.NET data readerem jako rozšíření nad rozhraním IDbConnetion. Porovnání rychlostí ukazuje tabulka dole, kde se testovalo 500 selectů a mapování vráceného výsledku na POCO objekty.

Porovnání rychlosti ORM frameworků – zdroj https://github.com/StackExchange/Dapper
MethodDuration
Hand coded (using a SqlDataReader)47ms
Dapper ExecuteMapperQuery49ms
ServiceStack.OrmLite (QueryById)50ms
PetaPoco52ms
BLToolkit80ms
SubSonic CodingHorror107ms
NHibernate SQL104ms
Linq 2 SQL ExecuteQuery181ms
Entity framework ExecuteStoreQuery631ms

Dapper kromě mapování na POCO objekty podporuje i mapování na dynamické objekty, ale výsledky jsou prakticky stejné. Další tabulky a srovnání najdete v oficiální dokumetnaci.

Instalace

Dapper je vyvíjen pod Open Source licencí Appache 2.0 a MIT Licence takže je volně k použití. Instalace Dapperu je velmi jednoduchá prostě si do projektu přidáte NuGet balíček https://www.nuget.org/packages/Dapper a máte hotovo. Případně přes konzolu:

Příklad použití

Další z řady výhod Dapperu je, že není implementován nad nějakou konkrétní databází. Jak už jsem psal Dapper rozšiřuje interface IDbConnection a může tak fungovat s kterýmkoliv ADO. NET providerem. Velmi jednoduše můžete vytvořit datovou vrstvu například s databází Oracle, MySQL, PostgreSQL, MS SQL nebo SQLite.

K dispozici máte metody Execute, Query, QueryFirst, QueryFirstOrDefault, QuerySingle, QuerySingleOrDefault, QueryMultiple plus jejich asynchronních verze. Abych mohl ukázat, jak se s Dapperem pracuje, potřebuji nějakou databázi a pár entit. Mějme tedy následující tabulky Invoice a InvoiceItem ve vazbě 1:N a k nim příslušné entity v C#.

Všechny příklady používají instanci SqlConnection (conn), kterou vrací metoda GetConnection(), ke spouštění commandů nad databází. Connection je potřeba před provedením příkazu otevřít a na konci taky zavřít. Na konci článku je testovací projekt, který si můžete stáhnout a příklady vyzkoušet.

Execute

Execute je základní metoda určená ke spouštění příkazů Insert, Update, Delte a Stored Procedury. Provede příkaz a vrátí počet ovlivněných řádků.

Na příkladu jsou vidět čtyři použití metody Execute pro příkaz insert. Příklady se liší akorát ve způsobu předání parametrů, kdy v prvních dvou případech je použit anonymní typ a pole anonymních typů a ve třetím a čtvrtém případě je použit pro předání parametrů objekt DynamicParameters. Stejným způsobem se pracuje i s příkazy typu update, delete.

Na metodě Execute je dobré, že dokáže přijmout pole parametrů a podle počtu záznamu v poli automaticky spustí příslušný počet příkazů. Takto nějak vypadá dotaz, který je spuštěn na serveru. Týká se to případu 2. Je vidět, že se opravdu spustí 2 příkazy sp_executesql.

Query

Metoda Query slouží pro získání záznamů z databáze. Má několik variant First, FirstOrDefault, Single a SingleOrDefault, které fungují obdobně jako podobně pojmenované metody v Linqu. Způsob vrácení výsledku ukazuje tabulka níže.

ResultNo ItemOne ItemMany Items
FirstExceptionItemFirst Item
SingleExceptionItemException
FirstOrDefaultDefaultItemFirst Item
SingleOrDefaultDefaultItemException

V příkladu 1 je ukázka použití standardní metody Query pro vytažení všech záznamů z tabulky Invoice. První řádek vrací seznam dynamických objektů. Na druhém řádku je použita generická Query metoda, která umožní přetypovat výsledek dotazu přímo na seznam příslušných Invoice objektů. Příklad dva potom ukazuje složitější select s podmínkou a předáním parametrů. Pro parametry platí stejná pravidla jako u metody Execute.

Procedura

Pokud chcete spustit stored proceduru, opět k tomu můžete využít metodu Execute jen navíc musíte zadat typ příkazu commandType: CommandType.StoredProcedure. Z procedury lze samozřejmě data i vrátit použít ale musíte metodu Query.

QueryMultiple

QueryMultiple je obdoba metody Query s tím rozdílem, že umožňuje jedním vrzem spustit i více různých dotazů. Metoda pak vrací objekt GridReader ze kterého voláním metody Read() můžete přečíst výsledky jednotlivých dotazů. V některých případech si takto můžete připravit jedním tahem data a ušetřit několik výletů na DB server.

MultiMapping

Při používání Dapperu můžete využít i tzv. MultiMapping. To znamená, že pokud váš objekt obsahuje vnořený objekt lze ho jedním selectem naplnit. Např. Když náš Invoice má několik InvoiceItem položek a chcete vytáhnout ty InvoiceItemy i s Invoicem můžu to provést následovně.

Generická metoda Query pak přijímá tři generické typy, kde první dva jsou dva vstupní typy a poslední třetí typ je ten co chcete z metody vrátit. V anonymní funkci (která je volána pro každý řádek výsledků) je pak zařízeno doplnění objektu Invoice do InvoiceItem. Parametrem metody spliOn : „IdInvoiceItem“ pak Dapperu řeknete, jak má výsledek dotazu rozsekat a kde začíná další objekt.

Je zde potřeba dát pozor na pořadí generických typů, argumentů anonymní metody a pořadí atributů podle kterého chcete objekt dělit. Metoda je na tom silně závislá a jakýkoliv překlep způsobuje v lepším případě nenamapování některého z objektů.

Nemyslím si ale, že je Dapper primárně k něčemu takovému určený. V případě složitějších objektů a hlouběji zanořených stromů objektů dá dost práce ty funkce napsat a je to navíc dost náchylné na chybu. Tady je potřeba zvážit, jestli nepoužít nějaký jiný framework, který toto zvládne dělat jednodušeji.

Transakce

Samozřejmostí je i možnost použití transakcí. Máte zde na výběr dvě možnosti, buď použijte objekt IDbTransaction, který musíte do metod předávat, nebo využijete TransactionScope.

Nebo transaction scope

Závěr

Na konec bych řek, že Dapper je slušný pomocník, pomocí kterého rychle vyrobíte databázovou vrstvu prakticky na jakémkoliv typu projektu. Jeho použití je opravdu jednoduché a naučit se to dá za pár hodin. Dapper je tak po právu nazýván králem mezi Micro ORM frameworky pro .NET. Já osobně navíc nejsem velký fanda různých připojených řešení a tenhle přístup se mi zamlouvá více než např. EntityFramework. Hodně sice záleží na typu aplikace, ale osobně mám raději, když mám dotazy pod kontrolu. Více o Dapperu se můžete dočíst na blogu Sama Saffrona a v oficiální dokumentaci na GitHubu.