F#使用参数设置SQLCommand的最佳方法

时间:2017-03-15 19:29:13

标签: parameters f# sqlcommand

我的F#程序需要与SQL Server通信。在一个部分我有这样的事情:

 let workFlowDetailRuncommand = new SqlCommand(query, econnection) 
    workFlowDetailRuncommand.CommandTimeout <- 100000
    workFlowDetailRuncommand.Parameters.Add("@1", SqlDbType.Int).Value <- 42
    workFlowDetailRuncommand.Parameters.Add("@2", SqlDbType.VarChar).Value <- "answer"
    workFlowDetailRuncommand.Parameters.Add("@3", SqlDbType.VarChar).Value <- mydate.ToString("yyyy.MM.dd")
    workFlowDetailRuncommand.Parameters.Add("@4", SqlDbType.VarChar).Value <- "D. Adams"
    workFlowDetailRuncommand.Parameters.Add("@5", SqlDbType.DateTime).Value <- DateTime.Now
    workFlowDetailRuncommand.Parameters.Add("@6", SqlDbType.Text).Value <- filename

是否有更多的自我表达方式(少输入!),而不是像这样一次设置一个参数。

2 个答案:

答案 0 :(得分:4)

我认为Bent的答案为构建标准SqlCommand对象提供了非常好的DSL。这可能正是你所需要的 - 如果你只是想要更好的语法来创建几个命令,它将完美地工作。

如果你想用你的SQL命令做更多的事情,那么DSL有一个限制,即它仍然基于底层的可变SqlCommand类型 - 它看起来很实用,但它改变了下面的对象封面,这可能会让你陷入困境。

更全面的选择是定义您自己的功能类型以捕获域 - 即您想要运行的查询类型:

type Parameter =
  | Int of int
  | VarChar of string
  | Text of string
  | DateTime of System.DateTime

type Command = 
  { Query : string 
    Timeout : int
    Parameters : (string * Parameter) list }

然后你可以使用普通的F#类型构建查询(你甚至可以像在Bent上建议的那样实现一个DSL,同时仍然保持不变):

let cmd = 
  { Query = query
    Timeout = 100000 
    Parameters = 
      [ "@1", Int 42
        "@2", VarChar "answer"
        "@3", VarChar (mydate.ToString("yyyy.MM.dd"))
        "@4", VarChar "D. Adams"
        "@5", DateTime DateTime.Now
        "@6", Text filename ] }

最后一点是编写一个带有命令和连接并将其转换为SqlCommand的函数:

let createSqlCommand cmd connection = 
  let sql = new SqlCommand(cmd.Query, connection) 
  sql.CommandTimeout <- cmd.Timeout
  for name, par in cmd.Parameters do
    let sqlTyp, value = 
      match par with
      | Int n -> SqlDbType.Int, box n
      | VarChar s -> SqlDbType.VarChar, box s
      | Text s -> SqlDbType.Text, box s
      | DateTime dt -> SqlDbType.DateTime, box dt
    sql.Parameters.Add(name, sqlTyp).Value <- value
  sql 

最好的方法取决于您的使用案例 - 与数据库的交互本质上是不纯的,因此保持孤立和不纯净的东西完全没问题。虽然我想将此作为一种可能的选择,但如果你想要更具功能性并专注于域(使用强大的域驱动建模方面的F#!)。

答案 1 :(得分:2)

我还没有测试过这个。

创建一些辅助函数。

let createSqlCommand query connection =
    new SqlCommand(query, connection)

let setTimeout timeout (sqlCommand: SqlCommand) =
    sqlCommand.CommandTimeout <- timeout
    sqlCommand

let addInt name (value: int) (sqlCommand: SqlCommand) =
    sqlCommand.Parameters.Add(name, SqlDbType.Int).Value <- value
    sqlCommand

像这样使用它们。

let mySqlCommand =
    createSqlCommand someQuery someConnection
    |> setTimeout 100000
    |> addInt "@1" 41
    |> addString "@s" "Hello"
    |> addDateTime "@dt1" DateTime.Now
    |> addFloat "@f1" 5.1

如果你有一个int,那么总是使用SqlDbType.Int是有意义的。

但是如果你有一个字符串,那么字段类型有几个明显的候选者。因此,让addXxx函数的名称反映字段类型而不是F#/ .NET类型可能是个好主意。这样你就可以创建addVarChar,addNVarChar,addChar等。

|> addInt "@i1" myInt
|> addDateTime "@dt1" myDateTime
|> addText "@tagText" myTagText
|> addNVarChar "@letter" myLetterBody