8

在 C# 中,我使用 sql 脚本将数据添加到 List 中,其中 T 将是一个类,其字段/属性映射到 sql 脚本。

我怎么能在 F# 中做到这一点?这篇文章以标准方式使用存储过程。

using (conn)
{
    conn.Open();
    using (SqlCommand cmd = new SqlCommand("dbo.query_here", conn))
    {
    cmd.CommandText = "dbo.query_here";
    cmd.CommandType = System.Data.CommandType.StoredProcedure;
    cmd.CommandTimeout = 600;
    cmd.Parameters.Add(new SqlParameter("@x1", Convert.ToString(x)));
    cmd.Parameters.Add(new SqlParameter("@y1", y));
    cmd.Parameters.Add(new SqlParameter("@z1", z));
    SqlDataReader reader = cmd.ExecuteReader();
    while (reader.Read())
    {
        MyListOfClasses.Add(new MyDataClass(reader.GetInt32(reader.GetOrdinal("x"))           
                                            reader.GetDouble(reader.GetOrdinal("y")),
                                            reader.GetDouble(reader.GetOrdinal("a")),
                                            reader.GetDouble(reader.GetOrdinal("b"))));
    }
    reader.Close();
}
conn.Close();

我意识到 F# 可能并不像这样直接,但我需要以类似的方式将这些数据放入 F# 列表中。也更喜欢本质上不起作用的建议,并遵循与 C# 代码类似的模式。

在以前的线程中,有人建议使用记录,但这仍然与 SqlDataReader 无关。最好有一个类列表,这样我就可以在每个项目上使用 getter 和 setter。

我应该在“为什么不只使用 C#”的不可避免的评论之前添加。很明显我可以使用 C#,但我正在探索用 F# 编写算法的可能性,为此我需要从 SQL Server 获取我的原始数据。

4

4 回答 4

12

如果您想results在 F# 列表中返回,列表推导式适合在这里使用。并且使用use关键字,您不需要显式处理对象。

use conn = (* Initialize sql connection here *)
conn.Open()
use cmd = new SqlCommand("dbo.query_here", conn)
cmd.CommandText <- "dbo.query_here"
cmd.CommandType <- System.Data.CommandType.StoredProcedure
cmd.CommandTimeout <- 600
cmd.Parameters.Add(new SqlParameter("@x1", Convert.ToString(x)))
cmd.Parameters.Add(new SqlParameter("@y1", y))
cmd.Parameters.Add(new SqlParameter("@z1", z))
use reader = cmd.ExecuteReader()
let results =
 [ while reader.Read() do
    yield new MyDataClass(reader.GetInt32(reader.GetOrdinal("x")),           
                          reader.GetDouble(reader.GetOrdinal("y")),
                          reader.GetDouble(reader.GetOrdinal("a")),
                          reader.GetDouble(reader.GetOrdinal("b"))) ]
于 2012-09-22T17:38:59.803 回答
8

使用普通的旧 ADO.NET 处理数据库实际上可以使用 F# 动态运算符非常好?。我写了一篇MSDN 文章,它实现了一个帮助程序,让您可以编写如下内容:

let myListOfClasses = 
  [ let db = new DynamicDatabase(connectionString)
    let rows = db.Query?query_here(string x, y, z)
    for r in rows do 
      yield MyDataClass(row?x, row?y, row?a, row?b) ]

这使用动态调用运算符?来调用存储过程 ( db.Query?query_here)。当你调用它时,你可以给它参数,就像它是一个普通的函数调用一样(它会将它们添加为 SQL 参数)。然后您还可以使用row?x读取属性 - 这从MyDataClass参数的类型推断类型,因此假设这些匹配,您不需要自己编写类型转换。

以下是讨论此问题的 MSDN 教程的链接:

于 2012-09-22T11:59:48.247 回答
5

你可以阅读这个

链接: http: //www.codeproject.com/Articles/95656/Using-a-DataRader-like-a-List-in-F

let rdr = cmd.ExecuteReader()

rdr
|> SomeRecord.asSeq                     // project datareader into seq<SomeRecord>
|> Seq.sumBy (fun r-> r.val1 * r.val2)  // now you can use all the Seq operators 
                                        // that everybody knows.
于 2012-09-22T11:42:07.953 回答
3

未经测试的 F# 翻译

use conn = ???
conn.Open()
using new SqlCommand("dbo.query_here", conn)(fun cmd ->

    cmd.CommandText <- "dbo.query_here"
    cmd.CommandType <- System.Data.CommandType.StoredProcedure
    cmd.CommandTimeout <- 600
    cmd.Parameters.Add(new SqlParameter("@x1", Convert.ToString(x)))
    cmd.Parameters.Add(new SqlParameter("@y1", y))
    cmd.Parameters.Add(new SqlParameter("@z1", z))
    let reader = cmd.ExecuteReader()
    while (reader.Read()) do
        MyListOfClasses.Add(new MyDataClass(reader.GetInt32(reader.GetOrdinal("x"))           
                                            reader.GetDouble(reader.GetOrdinal("y")),
                                            reader.GetDouble(reader.GetOrdinal("a")),
                                            reader.GetDouble(reader.GetOrdinal("b"))))

    reader.Close()
)
conn.Close()
MyListOfClasses.ToArray() |> List.ofArray
于 2012-09-22T11:49:34.423 回答