我编写了以下代码以在 F# 中执行 SQLServer StoredProc
module SqlUtility =
open System
open System.Data
open System.Data.SqlClient
SqlUtility.GetSqlConnection "MyDB"
|> Option.bind (fun con -> SqlUtility.GetSqlCommand "dbo.usp_MyStordProc" con)
|> Option.bind (fun cmd ->
let param1 = new SqlParameter("@User", SqlDbType.NVarChar, 50)
param1.Value <- user
cmd.Parameters.Add(param1) |> ignore
let param2 = new SqlParameter("@PolicyName", SqlDbType.NVarChar, 10)
param2.Value <- policyName
cmd.Parameters.Add(param2) |> ignore
Some(cmd)
)
|> Option.bind (fun cmd -> SqlUtility.ExecuteReader cmd)
|> Option.bind (fun rdr -> ExtractValue rdr)
let GetSqlConnection (conName : string) =
let conStr = ConfigHandler.GetConnectionString conName
try
let con = new SqlConnection(conStr)
con.Open()
Some(con)
with
| :? System.Exception as ex -> printfn "Failed to connect to DB %s with Error %s " conName ex.Message; None
| _ -> printfn "Failed to connect to DB %s" conName; None
let GetSqlCommand (spName : string) (con : SqlConnection) =
let cmd = new SqlCommand()
cmd.Connection <- con
cmd.CommandText <- spName
cmd.CommandType <- CommandType.StoredProcedure
Some(cmd)
let AddParameters (cmd : SqlCommand) (paramList : SqlParameter list) =
paramList |> List.iter (fun p -> cmd.Parameters.Add p |> ignore)
let ExecuteReader (cmd : SqlCommand ) =
try
Some(cmd.ExecuteReader())
with
| :? System.Exception as ex -> printfn "Failed to execute reader with error %s" ex.Message; None
这段代码有多个问题
首先,重复使用 Option.bind 非常烦人......并且会增加噪音。我需要一种更清晰的方法来检查输出是否为 None,如果不是,则继续。
最后应该有一个清理功能,我应该能够关闭+处置阅读器、命令和连接。但目前在管道的尽头,我所拥有的只是读者。
添加参数的函数......看起来它正在修改命令参数的“状态”,因为返回类型仍然是发送它的相同命令......添加了一些状态。我想知道一个更有经验的函数式程序员会如何做到这一点。
Visual Studio 在我进行异常处理的每个地方都会给我一个警告。有什么问题”它说
这种类型测试或向下转型将始终保持
我希望这段代码看起来是这样的
let x : MyRecord seq = GetConnection "con" |> GetCommand "cmd" |> AddParameter "@name" SqlDbType.NVarchar 50 |> AddParameter "@policyname" SqlDbType.NVarchar 50 |> ExecuteReader |> FunctionToReadAndGenerateSeq |> CleanEverything
您能否推荐我如何将我的代码提升到所需的水平以及任何其他改进?