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

Parameters F#使用参数设置SQLCommand的最佳方法,parameters,f#,sqlcommand,Parameters,F#,Sqlcommand,我的F#程序需要与SQL Server对话。在一部分中,我有如下内容: let workFlowDetailRuncommand = new SqlCommand(query, econnection) workFlowDetailRuncommand.CommandTimeout <- 100000 workFlowDetailRuncommand.Parameters.Add("@1", SqlDbType.Int).Value <- 42 workF

我的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
让workFlowDetailRuncommand=新建SqlCommand(查询、econnection)
workFlowDetailRuncommand.CommandTimeout我还没有测试过这个

创建一些辅助函数

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
如果您有一个int,那么始终使用SqlDbType.int是有意义的

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

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

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

如果您想用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,同时仍然保持不变):

最后一点是编写一个函数,该函数接受命令和连接,并将其转换为
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 
让createSqlCommand cmd连接=
让sql=newsqlcommand(cmd.Query,connection)
sql.CommandTimeout SqlDbType.Int,框n
|VarChar s->SqlDbType.VarChar,框s
|Text s->SqlDbType.Text,框s
|DateTime dt->SqlDbType.DateTime,框dt

Add(name,sqlTyp).Value在这里查看SqlCommandProvider。可能不完全适合您的用例(特别是在查询是动态的情况下),但可以很好地处理参数:我使用这种技术处理基于F#类型的大量XML的构造,它工作得非常好。这太棒了!我开始用它了。一个后续问题。由于SQLConnection支持Dispose,我一直在做
use connection=new SQLConnection(connString)
如何将其融入这个想法?@user1443098这就是为什么我没有在
命令中包含
SQLConnection
类型的原因-这样,您可以单独配置命令,然后使用
use
打开连接,调用
createSqlCommand
并运行SQL命令,然后关闭连接。仍然有必要的部分,但它被推到了最后。
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 ] }
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