Dapper 是個著重效能的羽量級微型 ORM。或許說「蠅量級」更適當,因為它真的很小,很快.....

平時存取資料庫時大多用 Entity Framework,但是像 Dapper 這樣小而美且快的 ORM,在某些場合其實也相當好用(stackoverflow.com 網站就有用這元件,因為作者 Sam Saffron 曾經參與該網站的開發工作) 。

多小呢?只需一個組件:Dapper.dll,檔案才 65~75 KB 左右(v1.13),名副其實的微型 ORM。不用參考一堆額外的 DLL 組件也就比較不會被長官發現偷用 3rd-party 元件,這點真的不錯。小就是美。

多快呢?有人實測並比較過幾種 ORM,Dapper 名列前茅(Dapper 網站上也有效能比較表)。連強調速度的 ServiceStack.OrmLite 也在自家網頁的推薦名單中把 Dapper 列為首位。

好用嗎?還是試了才知道。

首先要知道的是,Dapper 不管理資料庫連線的開啟和關閉——你得自行管理連線。了解這點,就可以開始用它來存取資料了。

建立練習專案

建立一個新的 Console 應用程式專案,目標平台 .NET 4.5(Dapper 也支援 .NET 3.5 和 .NET 4.0)。接著用 NuGet 加入 Dapper 套件。

假設要存取的資料庫是 Northwind,先建立一個 POCO 類別作為對應至 Customers 資料表的 entity。程式碼如下:

namespace DapperDemo.Models
{
    public class Customer
    {
        public string CustomerID { get; set; }
        public string CompanyName { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string Phone { get; set; }
    }
}

範例一:查詢資料

首先在程式碼當中引用 Dapper 命名空間,然後就跟使用傳統 ADO.NET API 的步驟類似:取得連線字串、建立連線、然後執行查詢命令。

Dapper 提供了一組擴充方法,讓實作 IDbConnection 介面的物件都增加了額外的功能。從底下這張截圖可以看到,IntelliSense 顯示我的 SqlConnection 物件有額外的 Query 方法可用:


這裡使用泛型版本的 Query 方法,以便將查詢結果自動對應至先前定義好的 Customer 物件的屬性。程式碼如下:

using System;
using System.Configuration;
using System.Data.SqlClient;
using Dapper;

namespace DapperDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            var cnstr = ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
            using (var cn = new SqlConnection(cnstr))
            {
                cn.Open();

                string sql = "select * from Customers where City like 'Mexico%'";
                var customers = cn.Query<Models.Customer>(sql);

                foreach (var cust in customers)
                {
                    Console.WriteLine(cust.CompanyName);
                }
            }

        }
    }
}

很簡單吧?

範例二:參數式查詢

前面的範例若要改成參數式查詢,可以建立匿名型別物件,並將 SQL 命令所需的參數包在裡面,傳給 Dapper 的 Query 方法。像這樣:

var sql = "select * from Customers where City like @@City or Country=@@Country";
var parameters = new 
{ 
    City = "Mexico%" ,
    Country = "UK"
};
var customers = cn.Query<Models.Customer>(sql, parameters);

範例三:執行無結果集的 SQL 命令

執行非查詢類的 SQL 命令,可使用 Execute 擴充方法:

sql = "insert into Customers (CustomerID, CompanyName, Address, City, Phone)" +
      " values (@@CustomerID, @@CompanyName, @@Address, @@City, @@Phone)";
var newCust = new Models.Customer()
{
    CustomerID = "Z001",
    CompanyName = "MikeSoft",
    Address = "大馬路黑暗巷",
    City = "台北市",
    Phone = "12345678"
};
int rowsChanged = cn.Execute(sql, newCust);

這裡帶入參數的寫法是採用具名型別,而範例二是採用匿名型別。兩種都可以。

Dapper 提供的這種帶入 SQL 參數的作法真是方便!

範例四:呼叫預儲程序

var spParams = new DynamicParameters();
spParams.Add("CustomerID", "ALFKI", DbType.String, ParameterDirection.Input);
var custHistories = cn.Query("CustOrderHist", spParams, commandType: CommandType.StoredProcedure);
foreach (var custHist in custHistories)
{
    Console.WriteLine(custHist.ProductName);
}

注意這次呼叫的 Query 方法並非泛型方法,所以傳回的結果會是動態型別的物件串列。這表示我們甚至可以不用預先定義前面的 Customer 類別,也能照樣使用 Dapper 的查詢方法。當然這也意味著寫程式時少了 IntelliSense 方便的參數提示,以及編譯時期的型別安全檢查。

Dapper 的 GitHub 網頁有更多範例可以參考。

小結

這個微型 ORM 不僅執行速度快、檔案小,而且學習成本低,只要原本熟悉 ADO.NET API,便能快速上手,實在方便好用。把這套件納入開發工具箱之後,以前自己寫的一些 AdoHelper 或 SqlHelper 之類的工具類別大概就不會再去使用了。

如果你也曾這麼想:「我只需要一套簡易的 API 讓我很方便的下 SQL 命令,並且自動幫我對應成物件就好了,別的甭管。」那麼,你可能會喜歡 Dapper。

Happy coding!