我的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
是否有更多的自我表达方式(少输入!),而不是像这样一次设置一个参数。
答案 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