如何在F#中包含存储过程

时间:2012-01-17 18:23:24

标签: sql-server f#

在下面的代码中,我想通过F#在SQL表中插入或更新行。 它需要一个代表用户的元组矩阵和一个相关分数(usrID,score),它们是一些F#计算的结果。
现在我想更新一个名为UserScoresTable的SQL表 我写的代码很有用,但速度很慢。

let cnn = new System.Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings.Item("Database").ConnectionString)
cnn.Open()

// Definition d'une fonction qui execute une demande sous MySQL
let execNonQuery s =
    let comm = new System.Data.SqlClient.SqlCommand(s, cnn, CommandTimeout = 10)
    comm.ExecuteNonQuery() |> ignore

// Definition d'une fonction qui utilise les éléments d'une matrice pour updater une table dans MySQL
let updateMySQLTable (m : Matrix<float * float>) =
    for j in 0 .. (snd m.Dimensions) - 1 do
        for i in 1 .. (fst m.Dimensions) - 1 do
        // first check if the user and score and date do not exist
            sprintf "IF NOT EXISTS (SELECT * FROM ProductScores WHERE UserID = %f AND ProductID = %f) INSERT INTO ProductScores (UserID, Score, Date) VALUES (%f, %f,CURRENT_TIMESTAMP)"  (fst m.[i, j]) (snd m.[i, j])
            |>  execNonQuery
       // otherwise update the row
            sprintf "UPDATE ProductScores SET Score = %f, Date = CURRENT_TIMESTAMP WHERE UserID = %f " (snd m.[i, j]) (fst m.[i, j])
            |>  execNonQuery

我想通过使用存储过程(例如

)来避免代码中的两个execNonQuery请求
CREATE PROCEDURE updateScoreByUsers 
    -- Add the parameters for the stored procedure here
    @UserID int, 
    @Score  float

AS
BEGIN

    IF NOT EXISTS 
    (SELECT * FROM ProductScores WHERE UserID = @UserID ) 
        INSERT INTO 
        ProductScores (UserID, Score, Date) VALUES (@UserID,@Score,CURRENT_TIMESTAMP)
    ELSE

    UPDATE ProductScores 
        SET Score = @Score, Date = CURRENT_TIMESTAMP 
        WHERE UserID = @UserID 
END
GO

但我不知道如何在F#中调用SQL存储过程 如何用F#调用它?
你还有其他改进方法吗?

2 个答案:

答案 0 :(得分:3)

SqlCommand.CommandText设置为存储过程的名称,并将CommandType设置为StoredProcedure。例如

use cmd = new SqlCommand("MyStoredProcedure", con)
cmd.CommandType <- CommandType.StoredProcedure
cmd.ExecuteNonQuery()

如果您在2008年,您可能需要查看MERGE声明。

要显着提高性能,您需要避免为每个项目进行数据库调用。也许使用SqlBulkCopy一次将所有数据加载到服务器(使用临时表或指定的临时表),然后使用基于集合的操作(UPDATE / INSERT / {{1 }})与目标表合并。

答案 1 :(得分:3)

正如其他人所指出的那样,只需在单个SQL命令中执行这两个语句就不会提高性能。为了使其真正高效,您需要将数据从Matrix传输到数据库,然后更新表。要复制数据,您可以使用SqlBulkCopy(请参阅MSDN for more info),这样可以有效地上传大量数据。您可以使用它在新表中插入数据,然后运行单个SQL命令来更新实际表中的数据。


除此之外 - Daniel的答案是从F#调用存储的proecdure的最直接方式。如果你想让它更好一点,你也可以使用动态运算符,让你写这样的东西:

db?MyStoredProcedure(userId, scores)

...而不是手动创建和执行SqlCommand。这可以使用this MSDN article中实现的DynamicDatabase类型来完成。