我认为 Bent 的答案为您提供了非常好的 DSL 来构建标准SqlCommand
对象。这很可能正是您所需要的 - 如果您只是想要更好的语法来创建几个命令,那么它将完美地工作。
如果你想用 SQL 命令做更多事情,那么 DSL 有一个限制,那就是它仍然基于底层可变的SqlCommand
type - 它看起来很实用,但它会在幕后改变对象,这可能会给你带来麻烦。
更全面的选择是定义您自己的函数类型来捕获域 - 即您想要运行的查询类型:
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# 的一侧!)。