如何让 F# fsx 脚本在每次从 C# 调用时重新执行和重新提取 SQL 数据?

How do I get an F# fsx script to re-execute and re-pull SQL data each time it's called from C#?

我编写了一个简单的 C# 网络应用程序,允许用户输入一些数据,然后单击按钮:

  1. 数据保存到本地SQLdb
  2. 调用 F# 脚本以使用 SqlCommandProvider 检索该数据
  3. 数据传回 C#
  4. 传回的数据用于某些计算
  5. 计算结果显示在网页屏幕上

一切正常,除了当多次单击按钮时,相同的数据从第一次执行时从 F# 发回。

似乎脚本没有像预期的那样重新执行,但如果是,似乎 SqlCommandProvider 可能锁定到它最初返回的第一组结果。

显然没有必要将数据发送到数据库并返回以执行这些计算。构建此应用是为了演示在解决方案中一起使用 F#/C#,而不是应用的实际高效生产使用。

#I "../packages/FSharp.Data.3.0.0/lib/net45"
#r "FSharp.Data.dll"
open FSharp.Data

#I "../packages/FSharp.Data.SqlClient.2.0.1/lib/net40"
#r "FSharp.Data.SqlClient.dll"
open FSharp.Data.SqlClient

[<Literal>]
let ConnectionString = 
    @"server=(local); database=CostPriceCalc; user id=MyId; password=MyPassword;"

[<Literal>]
let SqlQuery = "SELECT SharesSold, PricePerShare, SellDate, CostMethod FROM [CalcInputs] WHERE Id = (SELECT MAX(Id) FROM [CalcInputs])"
let cmd = new SqlCommandProvider<SqlQuery, ConnectionString>(ConnectionString)
let result = cmd.Execute() |> Seq.toArray

此外,我还没有正确处理从 F# 返回的数据,而是非常不优雅地只是转换为字符串并解析它以获得我需要的数据。然而,这似乎无关紧要(除了它非常不正确),因为 C# 变量在从 F# 拉出之前每次都是清除的,并且相同的数据每次都从 F# 返回。

   public static List<NewData.Values> ParseFsharpData()
    {
        var parsedList = new List<NewData.Values>();
        foreach (var item in CalculateCostPrice.result)
        {
            var parsedData = item.ToString().Replace(";", ",").
                Replace("{ ", "").Replace(" }", "").Replace("Some ", "").
                Replace("M,", ",").Replace("\"", "").
                Split(',').ToList();
            parsedList = (from value in parsedData
                select new NewData.Values
                {
                    Value1 = value.Split('=')[0].Trim(),
                    Value2 = value.Split('=')[1].Trim()
                }).ToList();
        }
        return parsedList;
    }

最后,我确认新数据正在正确写入数据库。该问题似乎仅限于 F# fsx 脚本本身(名为 CalculateCostPrice)未按预期重新执行,或者 SqlCommandProvider 缓存数据。

我还没有尝试编译 .fsx 脚本,但我在 F# 项目中使用模块的经验让我认为:

let result = cmd.Execute() |> Seq.toArray

编译为 CalculateCostPrice class 上的静态变量。这意味着它只会执行一次(第一次使用时,如果不是更早的话),结果将存储在 "result" 变量中。

添加类型为 "unit" 的参数应该将其更改为方法(同样,尚未测试):

let result() = cmd.Execute() |> Seq.toArray

您可以从 C# 调用它:

foreach (var item in CalculateCostPrice.result())

在这种情况下,执行将在您调用方法时发生,而不是在 class 初始化时发生。我可能会将其从 "result" 重命名为 "executeQuery" 或类似的名称。