2012-02-15 81 views
4

我一直在試圖找出從F#插入SQL Server的方法。F#向SQL Server插入一個列表

我有一個F#函數,可以在用戶定義的模式之後遍歷文件夾內的所有文件。然後我可以使用返回的數據放入列表或(理想情況下)插入到數據庫中。

我已經有一個工作嵌入到-SQL函數可以正常工作:

let execNonQuery conn s = 
let comm = 
    new SqlCeCommand(s, conn) 
try 
    comm.ExecuteNonQuery() |> ignore 
with e -> 
    printf "Error : %A\n" e 

let string = "insert into MyTable (MyColumn) values ('test .. again')" 
execNonQuery conn string; // works 

我試圖讓這個方法才能正常工作:

let rec getAllFiles dir pattern = 
    seq { yield! Directory.EnumerateFiles(dir, pattern) 
      for d in Directory.EnumerateDirectories(dir) do 
       yield! getAllFiles d pattern } 

let getApplications (dir : string) (extension : string) = 
    getAllFiles dir extension 
    //|> Seq.toList // If I need to create a list of returned values 
    |> Seq.iter (fun s -> SQLInsertString s) // This does not work as it complains about the function not being of type unit 

如果我使用Seq.toList只能按以下方式調用函數,它的工作原理:

getApplications "C:\Admin" "*.txt" // works 

另一件我不明白的事情是,如何創建一個接受Value的字符串的工作插入命令。例如:

let SQLInsertString s = "insert into MyTable (MyColumn) values (%s)" //does not work 

回答

4

傳遞參數的最佳方式一個查詢是使用SqlCeParameter。這比編寫字符串更容易(因爲您不需要編碼字符串和轉義引號)並且它也更安全,因爲您避免了SQL injection attack。這是一個基本的例子:

let sqlInsertString value = 
    // Create and open connection ('use' makes sure it gets closed at the end) 
    use conn = new SqlCeConnection("..."); 
    conn.Open() 
    // Create a command with a parameter named '@str' 
    let cmd = new SqlCeCommand("INSERT INTO MyTable (MyColumn) values (@str)", conn) 
    // Create parameter '@str' with string value 'value' and add it to the command 
    let param = new SqlCeParameter("@str", SqlDbType.NVarChar, value) 
    cmd.Parameters.Add(param) 
    // Now run the command (exception handling omitted) 
    cmd.ExecuteNonQuery() |> ignore 

使用此功能,您現在應該能夠使用Seq.iter。該功能需要一個string插入並返回unit(沒有值),因此它可以被傳遞到Seq.iter

let getApplications (dir : string) (extension : string) = 
    getAllFiles dir extension 
    |> Seq.iter (fun s -> sqlInsertString s) 

或者,你可以寫的最後一行,就像|> Seq.iter sqlInsertString。如果你這樣做,你基本上是說,參數s應該直接傳遞給sqlInsertString函數。

+0

非常感謝Tomas,作品像一個魅力。現在我也看到了它更好 – 2012-02-15 15:35:45

5

你快到了。問題是sqlInsertString返回string這是不合法的使用Seq.iter

你在做什麼與sqlInsertString是使用字符串格式創建一個字符串。

let sqlInsertString s = 
    sprintf "insert into MyTable (MyColumn) values (%s)" s 

現在你可以使用execNonQuerysqlInsertString結果實際數據插入到數據庫:它具有sprintf功能非常適合。由於execNonQuery回報unit,它可以很容易地在Seq.iter使用:

// Assuming conn is a global and already defined variable. 
let getApplications (dir : string) (extension : string) = 
    getAllFiles dir extension 
    |> Seq.iter (fun s -> execNonQuery conn (sqlInsertString s)) 

由於類型的註釋是多餘的,你的代碼可以在一個更地道的方式改寫:

let getApplications dir extension conn = 
    getAllFiles dir extension 
    |> Seq.iter (sqlInsertString >> execNonQuery conn) 
+0

非常感謝。這個答案也像一個魅力。我不得不選擇一個答案作爲預期的答案,Tomas解釋瞭如何使用參數。 – 2012-02-15 15:35:24