Jef*_*ner 3 ado.net f# haskell hdbc
我对Haskell的简洁和优雅感到震惊.但是我在一个.Net的房子里工作,所以当我能够逃脱它时,我会使用F# - 我可能是全国数百名使用它的人中唯一一个.
ADO.NET或F#是否提供与HDBC一样简洁优雅的东西executeMany?我正在通过真实世界Haskell.在第21章中,它提供了这个例子:
ghci> conn <- connectSqlite3 "test1.db"
ghci> stmt <- prepare conn "INSERT INTO test VALUES (?, ?)"
ghci> executeMany stmt [[toSql 5, toSql "five's nice"], [toSql 6, SqlNull]]
ghci> commit conn
ghci> disconnect conn
Run Code Online (Sandbox Code Playgroud)
我想在我的F#中获得这种优雅和简洁.我已经看到很多关于使用参数化查询以避免SQL注入攻击的炒作.在这种情况下,我没有使用它们有三个原因:
这是我的F#代码:
module Data
open System
open System.Data
open System.Data.OleDb
open System.Text.RegularExpressions
type Period = Prior | Current
let Import period records db =
use conn = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + db + ";Persist Security Info=False;")
let execNonQuery s =
let comm = new OleDbCommand(s, conn) in
comm.ExecuteNonQuery() |> ignore
let enquote = sprintf "\"%s\""
let escapeQuotes s = Regex.Replace(s, "\"", "\"\"")
let join (ss:string[]) = String.Join(",", ss)
let table = match period with
| Prior -> "tblPrior"
| Current -> "tblCurrent"
let statements =
[| for r in records do
let vs = r |> Array.map (escapeQuotes >> enquote) |> join
let vs' = vs + sprintf ",\"14\",#%s#" (DateTime.Now.ToString "yyyy-MM-dd") in
yield sprintf "INSERT INTO %s ( [Field01], [Field02], [Field03] [Field04], [Field05], [Field06], [Field07], [Field08], [Field09], [Field10], [Field11], [Field12], [Field13], [Field14], [Field15], [Field16], [Field17], [Field18], [Field19], [Field20], [Field21], [Field22], [Field23], [Field24], [Field25], [Field26], [Field27], [Field28], [Field29], [Field30], [Field31], [Field32], [Field33], [Field34] ) VALUES (%s)" table vs' |] in
do conn.Open()
execNonQuery (sprintf "DELETE FROM %s" table)
statements |> Array.iter execNonQuery
Run Code Online (Sandbox Code Playgroud)
出于安全原因,我已经重命名了表格的字段.
因为表上的所有字段都是文本,所以我可以轻松地将它们Array.map它们转义并引用值.
每天要将9,000到10,000条记录导入到两个表中的每一个表中,我希望尽可能高效地执行此操作.因此我对executeManyHaskell 感兴趣.但是,我喜欢参数化查询背后的想法,我喜欢Hasekll实现它们的方式.在F#中,是否存在与简洁和优雅相同的东西?
我同意@JonnyBoats评论,通常使用像SqlDataConnection(LINQ-to-SQL)或SqlEntityConnection(实体框架)这样的F#SQL类型提供程序将比任何涉及手动构建insert语句字符串的解决方案更优雅.
但是,你的问题还有一个重要的限定符:"每天要将9,000到10,000条记录导入到两个表中的每一个,我希望尽可能高效地完成这项工作." 在这样的场景中,您将希望使用SqlBulkCopy进行有效的批量插入(它利用本机数据库驱动程序功能,以获得比HDBC更快的插入速度executeMany).
这是一个小例子,可以帮助您开始使用SqlBulkCopyF#:https://stackoverflow.com/a/8942056/236255.请注意,您将使用DataTable来暂存数据,这些数据虽然陈旧但在F#中使用起来有些尴尬,但在我看来仍然优于构建插入语句字符串.
更新以回应评论
这是一个使用的通用方法,SqlBulkCopy它针对您的场景进行了改进(我们将列规范与行数据分开传递,并且两者都是动态的):
//you must reference System.Data and System.Xml
open System
open System.Data
open System.Data.SqlClient
let bulkLoad (conn:SqlConnection) tableName (columns:list<string * Type>) (rows: list<list<obj>>) =
use sbc = new SqlBulkCopy(conn, SqlBulkCopyOptions.TableLock, null, BatchSize=500, BulkCopyTimeout=1200, DestinationTableName=tableName)
sbc.WriteToServer(
let dt = new DataTable()
columns
|> List.iter (dt.Columns.Add>>ignore)
for row in rows do
let dr = dt.NewRow()
row |> Seq.iteri(fun i value -> dr.[i] <- value)
dt.Rows.Add(dr)
dt)
//example usage:
//note: since you know all your columns are of type string, you could define columns like
//let columns = ["Field1", "Field2", "Field3"] |> List.map (fun name -> name, typeof<String>)
let columns = [
"Field1", typeof<String>
"Field2", typeof<String>
"Field3", typeof<String>
]
let rows = [
["a"; "b"; "c"]
["d"; "e"; "f"]
["g"; "h"; "i"]
["j"; "k"; "l"]
["m"; "n"; "o"]
]
//a little funkiness to transform our list<list<string>> to list<list<obj>>,
//probably not needed in practice because you won't be constructing your lists literally
let rows = rows |> List.map (fun row -> row |> List.map (fun value -> value :> obj))
bulkLoad conn "tblPrior" columns rows
Run Code Online (Sandbox Code Playgroud)
使用涉及反射的方法,你可以得到更好的/更简洁的东西.例如创建类似的类型
type RowData = { Field1:string; Field2:string; Field3:string }
Run Code Online (Sandbox Code Playgroud)
并使用bulkLoad带有list<'a>参数的签名创建一个参数,使其反映typeof<'a>构建的属性名称和类型DataTable Columns,并类似地使用反射迭代行实例的所有属性以创建和添加新行DataTable.事实上,这个问题展示了如何制作一个通用的ToDataTable方法(在C#中).
| 归档时间: |
|
| 查看次数: |
497 次 |
| 最近记录: |