我编写了以下代码来在F#中执行SQLServer存储过程:
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,如果不是,则继续执行。
最后应该有一个cleanupfunction,我应该能够关闭+释放reader、command和connection。但目前,在管道的末尾,我只有reader。
添加参数的函数...看起来像是修改了命令参数的“状态”,因为返回类型仍然是发送的相同命令...带有一些添加的状态。我想知道一个更有经验的函数式程序员将如何完成这个任务。
Visual Studio在每个处理异常的地方都给我一个警告。这有什么问题?它说
这种类型测试或向下转换始终有效
我希望代码看起来像这样:
let x:MyRecord序列= GetConnection“con”|> GetCommand“cmd”|> AddParameter“@name”SqlDbType.NVarchar 50 |> AddParameter“@policyname”SqlDbType.NVarchar 50 |> ExecuteReader |> FunctionToReadAndGenerateSeq |> CleanEverything
您能推荐我如何将代码提升到所需的水平,以及任何其他改进吗?