F# 優雅使用Dapper進行資料庫操作

fairjm發表於2016-09-14

本文來自圖靈社群@fairjm 轉截請註明出處


之前寫過一篇用SQLProvider進行資料庫連線的,但實際使用的時候發現相容性不是很好,在用mysql的時候很多表都找不到,要反覆rebuild.

直接使用ADO.NET的話就顯得麻煩.
來看一下ADO.NET一個查詢到例子

let cStr = @"Server=地址;Port=埠;Database=資料庫名稱;Uid=使用者名稱;Pwd=密碼;"
use conn = new MySqlConnection(cStr)
let command = conn.CreateCommand(CommandText = "SELECT * FROM user LIMIT 1",
                                 CommandType = CommandType.Text)
conn.Open()
use reader = command.ExecuteReader()
let idOrder = reader.GetOrdinal("userid")

if reader.Read() then
    // int 可以用string
    printfn "%s" <| reader.GetString(idOrder)
    printfn "%d" <| reader.GetInt32("userid")
    printfn "%s" <| reader.GetString("username")
    printfn "%A" <| reader.GetDateTime("created")
    // date 也可以用string
    printfn "%s" <| reader.GetString("created")
reader.Close()
conn.Close()

如果要用引數化的話還需要以下程式碼來設定SqlCommand

//建立SqlCommand物件
SqlCommand cmd = conn.CreateCommand();             
//預設就是text
cmd.CommandType = CommandType.Text;
//sql語句
cmd.CommandText = "select * from products = @ID";  
cmd.Parameters.Add("@ID", SqlDbType.Int);
//給引數sql語句的引數賦值
cmd.Parameters["@ID"].Value = 1;

作為常常寫指令碼的工具,我對資料庫查詢的需求是使用簡單方便,因為是寫指令碼,所以不會涉及到很多表的JOIN,一對多,多對多的處理等等,能方便讀取行資料就可以了.

這一點Dapper可以很好滿足.Dapper可以使用dynamic object作為查詢引數和返回結果.
但FSharp似乎沒有直接使用dynamic object的方式(有的話歡迎打臉...沒找著),這裡可以借用第三方的專案來.比如FSharp.Interop.Dynamic.
使用之後構建查詢就方便多了:

let query =  ExpandoObject()
query?userId <- 1

也可以直接解析返回結果

需要的擴充套件:

Install-Package FSharp.Interop.Dynamic
Install-Package MySql.Data -Version 6.9.9
Install-Package Dapper  

程式碼:

open MySql.Data.MySqlClient
open FSharp.Interop.Dynamic
open Dapper
open System
open System.Dynamic

let getConnection (addr, user, pass, db, port) =
    let builder = new MySqlConnectionStringBuilder()
    builder.Server <- addr
    builder.UserID <- user
    builder.Password <- pass
    builder.Database <- db
    builder.Port <- port
    let conn = new MySqlConnection(builder.ConnectionString)
    conn.Open()
    conn

let conn = getConnection("","","","",3306)
let query =  ExpandoObject()
query?userId <- 1
let obj = conn.QueryFirst("select * from user where userid = @userId", query)
let objs = conn.Query("select * from user limit 10")
printfn "%A" obj?username
objs
|> Seq.iter (fun e -> printfn "%s" e?username)
conn.Close()

對比上面ADO.NET的例子 使用就比較簡單直接了~
還有one to many的例子有點長 可以看gist的程式碼: https://gist.github.com/fairjm/8d2c8b2fd8db549364447a78d2bdad4f

相關文章