[ASP.NET] Dapper - 輕量級ORM
在寫商用應用系統,使用到資料庫是避免不了的,所以身為開發人員其實很多時候都是跟資料庫語法在奮戰,在 .NET 程式裡使用DataTable、DataSet是很稀鬆平常的事情,但是使用DataTable、DataSet這類弱型別的東西通常會帶來一個比較不好的現象,就是當你資料名稱打錯時,往往必須在程式跑起來的時候才會發現到,因此享受不到強型別的好處,可以在開發設計階段就識別出來。另外直接在畫面程式裡充滿一堆SQL資料庫操作語言,並不是件好事情,這會讓你的程式職責混亂,維護困難。但對於已現存的專案或是已熟悉習慣大量操控SQL語言的團隊來話,在短時間內要求改用Entity Framework或是其它大型的ORM Framework來說,可能不是那麼的容易,就人性來說往往會產生抗拒,這並不是我們樂見的,但是我們也不樂見於團隊持續處於以往意大利麵式的開發習慣,所以採用漸進式的改變可能是比較好的一種方式。因此首先我們要來思考一下,如果我們可以先把程式裡對於資料庫的操作改成DTO的方式,這樣一來前端檢視畫面的程式,可以享用強型別的好處,而背後類別庫也讓一部開發人員持續保有撰寫SQL資料庫操作語言的彈性,這樣的改變或許在第一步會比較容易跨出去。
要做到DTO,首先要面對的就是Data Mapping Object的問題,前面一開始提到如果一開始就使用Entity Framework或是其它大型的ORM Framework,可能改變太大,更何況一開始我們也不需要Entity Framework裡其它的功能(例如資料庫定義自動更新之類的),需求是很簡單只須先做到可以Data Mapping Object就好,因此這個時候可能會選擇使用Reflection自行撰寫Helper來達到,例如
1: PropertyInfo property = instance.GetType().GetProperty(idr.GetName(i), BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
2:
3: if (property != null)
4: {
5: if (property.PropertyType.Equals(typeof(string)))
6: {
7: if (!string.IsNullOrEmpty(idr.GetValue(i).ToString()))
8: property.SetValue(instance, idr.GetValue(i));
9: }
10: else if (property.PropertyType.Equals(typeof(Guid?)))
11: {
12: if (!string.IsNullOrEmpty(idr.GetValue(i).ToString()))
13: property.SetValue(instance, new Guid(idr.GetValue(i).ToString()));
14: else
15: property.SetValue(instance, null);
16: }
17: ......
18: ......
19: ......
20: }
不過最近在一場活動中聽到了Dapper這個小而美的輕量級ORM,Dapper 使用起來不像Entity Framework必須在專案裡定義一堆Schema,只須在專案內參考Dapper的dll就可以了,只要是實作IDbConnection 介面都可以具有Dapper 所提供的額外擴充方法,使用上很簡單,程式碼不會改到太多地方,開發上一樣採用熟悉的ADO.NET,以下就用一個簡單的例子來示範。
範例
首先我們建立一個ASP.NET MVC的專案(不一定要ASP.NET的專案,其它專案型式也可以),接著從NuGet上取得Dapper,加入至專案內,事實上可以發現Dapper只有一顆dll而已。
接著我們要定義一個 Person 的DTO類別,用來承接資料轉化為物件,對應範例資料庫的 Person 資料表,在這裡我只定義四個屬性,實際資料表不只四個欄位。
接著 using Dapper 後,再來就像寫原本的ADO.NET一樣,定義SqlConnection物件,然後可以發現SqlConnection物件多出一些Query的擴充方法,顧名思議就是可以直接進行 SQL Command的Query。
1: using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["DemoDbConnection"].ConnectionString))
2: {
3:
4: result = conn.Query<Person>("select * from Person.Person where BusinessEntityID<=@BusinessEntityID").ToList();
5: }
當然也可以帶查詢參數,在這裡我使用匿名型別來進行,只查詢BusinessEntityID<=10的資料。
1: using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["DemoDbConnection"].ConnectionString))
2: {
3: var para = new
4: {
5: BusinessEntityID = 10
6: };
7: result = conn.Query<Person>("select * from Person.Person where BusinessEntityID<=@BusinessEntityID", para).ToList();
8: }
另外 Dapper 也可以進行批次執行,或是一次對應到多個類別等等,功能其實相當的強大便利,在官方網站提供了不少範例,可以自行參考之(https://github.com/StackExchange/dapper-dot-net),若您關心效能的話,Dapper 本身很有自信的告訴我們,它是非常快的,在官方網站也提供了相關數據,在支援度方面,Dapper 目前可以支援全部.net ADO providers。
結語
如果您的團隊不想導入或是因某些因素考量而無法導入像Entity Framework這種大型的ORM Framework,但又想讓團隊在開發上能導向強型別的設計模式,那麼 Dapper 或許會是一個很不錯的選擇。
Dapper : https://github.com/StackExchange/dapper-dot-net
By No.18