簡體   English   中英

F#和ADO.NET - 慣用F#

[英]F# and ADO.NET - idiomatic F#

我剛開始學習F#。 我昨晚寫了這個F#/ ADO.NET代碼。 你會以什么方式改進語法 - 讓它感覺像是慣用的F#?

    let cn = new OleDbConnection(cnstr)
    let sql = "SELECT * FROM People"
    let da = new OleDbDataAdapter(new OleDbCommand(sql, cn))
    let ds = new DataSet()
    cn.Open()
    let i = da.Fill(ds)
    let rowCol = ds.Tables.[0].Rows
    let rowCount = rowCol.Count
    printfn "%A" rowCount

    for i in 0 .. (rowCount - 1) do
        let row:DataRow = rowCol.[i]
        printfn "%A" row.["LastName"]

注意:我確實發現語法檢查器不喜歡rowCol。[i]。[“LastName”]處理雙索引器的正確方法是什么? 我不得不將代碼分成兩行。

另外,如果我沒有沿着DataSet路由走下去並使用將其數據加載到F#記錄中的SqlDataReader。 我應該使用什么樣的集合結構來包含記錄? 標准的.NET List <>?

代碼的關鍵部分是處理不起作用的.NET API,因此無法使代碼的這一部分更具慣用性或更好。 但是,函數式編程中的關鍵是抽象 ,因此您可以將這個(丑陋)代碼隱藏到一些慣用和可重用的函數中。

為了表示F#中的數據集合,您可以使用標准F#列表類型(適用於功能數據處理)或seq<'a> (封面下的標准.NET IEnumerable<'a> ),它可以很好地工作使用其他.NET庫時。

根據您在代碼中的其他位置訪問數據庫的方式,以下可能有效:

// Runs the specified query 'sql' and formats rows using function 'f'
let query sql f = 
  // Return a sequence of values formatted using function 'f'
  seq { use cn = new OleDbConnection(cnstr) // will be disposed 
        let da = new OleDbDataAdapter(new OleDbCommand(sql, cn)) 
        let ds = new DataSet() 
        cn.Open() 
        let i = da.Fill(ds) 
        // Iterate over rows and format each row
        let rowCol = ds.Tables.[0].Rows 
        for i in 0 .. (rowCount - 1) do 
            yield f (rowCol.[i]) }

現在您可以使用query函數來編寫原始代碼,大致如下:

let names = query "SELECT * FROM People" (fun row -> row.["LastName"])
printfn "count = %d" (Seq.count names)
for name in names do printfn "%A" name

// Using 'Seq.iter' makes the code maybe nicer 
// (but that's a personal preference):
names |> Seq.iter (printfn "%A")

你可以寫的另一個例子是:

// Using records to store the data
type Person { LastName : string; FirstName : string }
let ppl = query "SELECT * FROM People" (fun row -> 
  { FirstName = row.["FirstName"]; LastName = row.["LastName"]; })

let johns = ppl |> Seq.filter (fun p -> p.FirstName = "John")

順便說一下:關於Mau的建議,如果有更直接的方法使用像for這樣的語言結構編寫代碼,我就不會過度使用高階函數。 以上iter的例子很簡單,有些人會發現它更具可讀性,但沒有一般規則......

在ADO.NET上為F#編寫了一個函數包裝器 使用此庫,您的示例如下所示:

let openConn() =
   let cn = new OleDbConnection(cnstr)
   cn.Open()
   cn :> IDbConnection

let query sql = Sql.execReader (Sql.withNewConnection openConn) sql

let people = query "select * from people" |> List.ofDataReader
printfn "%d" people.Length
people |> Seq.iter (fun r -> printfn "%s" (r?LastName).Value)

好吧,你可以在第一位改變,但是無論何時處理數據集合,如最后幾行,你都可以使用內置的Seq,List,Array函數。

for i in 0 .. (rowCount - 1) do
  let row:DataRow = rowCol.[i]
  printfn "%A" row.["LastName"]

=

rowCol |> Seq.cast<DataRow> 
       |> Seq.iter (fun row -> printfn "%A" row.["LastName"])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM