2012-09-23 4 views
5

나는 F 번호에 SQLServer에의 StoredProc가를 실행하기 위해 다음과 같은 코드를 작성데이터베이스 연결 및 F #을

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 

나는 무엇보다도이 코드

  1. 첫 번째와 Option.bind의 반복 사용으로 여러 문제가 매우 자극적이며 ... 소음이 추가됩니다. 출력이 없음인지 아닌지 확인하고 그렇지 않은 경우 더 명확한 방법이 필요합니다.

  2. 마지막에는 리더, 명령 및 연결을 닫고 + 처리 할 수있는 정리 기능이 있어야합니다. 그러나 현재 파이프 라인의 끝에는 독자가 있습니다.

  3. 매개 변수를 추가하는 함수는 반환 된 매개 변수가 여전히 추가 된 상태와 함께 전송 된 명령과 동일하기 때문에 명령 매개 변수의 "상태"를 수정하는 것처럼 보입니다. 좀 더 숙련 된 프로그래머가이 작업을 어떻게 처리했는지 궁금합니다.

  4. Visual Studio에서는 예외 처리를 수행하는 곳마다 경고 메시지를 표시합니다. 사기꾼 "그게 뭐가 잘못"데 MyRecord 서열 =의 getConnection은

이 형식 시험이나 내리 뜬 항상

이 코드는보고 싶지 방법이

하자 x는 개최 말한다 " |> GetCommand "cmd를"|> AddParameter "@name"SqlDbType.NVarchar 50 |> AddParameter "@policyname"SqlDbType.NVarchar 50 |>가 ExecuteReader |> FunctionToReadAndGenerateSeq |

당신이 추천 할 수> CleanEverything는 어떻게 내 코드를 취할 수 있습니다 원하는 수준 및 다른 개량?

답변

7

나는 실패한 계산을 나타내는 옵션을 사용하는 것이 순전히 기능적인 langauges에 더 적합하다고 생각합니다. F #에서는 계산이 실패했다는 것을 나타내는 예외를 사용하는 것이 완벽합니다.

코드는 단순히 예외를 None 값으로 변환하지만이 상황을 실제로 처리하지는 않습니다. 이는 코드 호출자에게 맡깁니다 (누가 None과 관련하여 결정해야합니다). 예외를 처리하도록 허용 할 수도 있습니다. 예외에 더 많은 정보를 추가하려면, 사용자 자신의 예외 유형을 정의한 후 표준 예외를 벗어나는 대신 예외를 던집니다.

다음은 그것을 던질 새로운 예외 유형과 간단한 함수를 정의 : F 번호 기능을 사용하여 몇 단순화와 일반 .NET 스타일을 사용

exception SqlUtilException of string 

// This supports the 'printf' formatting style  
let raiseSql fmt = 
    Printf.kprintf (SqlUtilException >> raise) fmt 

를 코드는 훨씬 간단 같습니다

// Using 'use' the 'Dispose' method is called automatically 
let connName = ConfigHandler.GetConnectionString "MyDB" 
use conn = new SqlConnection(connName) 

// Handle exceptions that happen when opening the connection 
try conn.Open() 
with ex -> raiseSql "Failed to connect to DB %s with Error %s " connName ex.Message 

// Using object initializer, we can nicely set the properties 
use cmd = 
    new SqlCommand(Connection = conn, CommandText = "dbo.usp_MyStordProc", 
        CommandType = CommandType.StoredProcedure) 

// Add parameters 
// (BTW: I do not think you need to set the type - this will be infered) 
let param1 = new SqlParameter("@User", SqlDbType.NVarChar, 50, Value = user) 
let param2 = new SqlParameter("@PolicyName", SqlDbType.NVarChar, 10, Value = policyName) 
cmd.Parameters.AddRange [| param1; param2 |] 

use reader = 
    try cmd.ExecuteReader() 
    with ex -> raiseSql "Failed to execute reader with error %s" ex.Message 

// Do more with the reader 
() 

.NET 코드와 비슷하지만 완벽합니다. F #에서 데이터베이스를 다루는 것은 명령형을 사용하고 코드를 숨기려고하면 코드가 혼란스럽게됩니다.이제, 당신이 사용할 수있는 다른 깔끔한 F 번호 기능의 숫자가 - 동적 사업자 ? 특히 지원, 당신 같은 줄 것이다 : 볼이에 대한 자세한 내용은 다음 MSDN 시리즈를

let connName = ConfigHandler.GetConnectionString "MyDB" 

// A wrapper that provides dynamic access to database 
use db = new DynamicDatabase(connName) 

// You can call stored procedures using method call syntax 
// and pass SQL parameters as standard arguments 
let rows = db.Query?usp_MyStordProc(user, policy) 

// You can access columns using the '?' syntax again 
[ for row in rows -> row?Column1, row?Column2 ] 

는 :