F#向SQL Server插入一个列表

问题描述:

我一直在试图找出从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 

传递参数的最佳方式一个查询是使用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

你快到了。问题是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