我现在正试图找出一种从F#插入SQL Server的方法。
我有一个F#函数,它按照用户定义的模式遍历文件夹中的所有文件。然后我可以使用返回的数据放入列表或(理想情况下)插入数据库。
我已经有一个正常工作的insert-into-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
答案 0 :(得分:5)
你快到了。问题是sqlInsertString
返回string
,这在Seq.iter
中使用是不合法的。
您对sqlInsertString
所做的是使用字符串格式创建字符串。它非常适合sprintf
函数:
let sqlInsertString s =
sprintf "insert into MyTable (MyColumn) values (%s)" s
现在,您可以在execNonQuery
的结果上使用sqlInsertString
来实际将数据插入数据库。由于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)
答案 1 :(得分: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
函数。