“自动”将SQL Server表传输到F#矩阵

时间:2011-10-28 15:05:25

标签: sql-server f# import matrix

我有以下代码从SQL导入到F#并将信息转换为矩阵。

我这里有一个用户有4个标准的例子,但如果我想再添加2个标准(并且标准的数量可能会改变),我将不得不手动完成(在此代码中维度不会自动完成)并且必须写入列的名称)。

此解决方案有效,但我必须手动检查SQL表中的演进,并手动更改代码中列的名称,这很快就会非常痛苦。所以我的问题是:

您是否看到了自动考虑SQL表的维度的方法,更一般地说,您是否有办法进行此导入而无需手动编写每列的名称(“Criteria0_ID”等等) SQL中“列”的名称?)?提前告诉我们!

type user = {
    Criteria0_ID :  int;
    Criteria1_ID : int;
    Criteria2_ID : int;
    Criteria3_ID : int}

// Extraction from SQL

module ReadSQl =

    let GetUsers = seq { 
        let connStr = new SqlConnectionStringBuilder(DataSource="localhost\sqlexpress", IntegratedSecurity=true, InitialCatalog="TestExtractionF#")
        use cnn = new SqlConnection(connStr.ConnectionString)
        use cmd = new SqlCommand("SELECT * FROM SyntheseTest", cnn)
        cnn.Open()

        use reader = cmd.ExecuteReader()
        while reader.Read() do
        yield {
               Criteria0_ID = unbox(reader.["Criteria0_ID"])
               Criteria1_ID = unbox(reader.["Criteria1_ID"])
               Criteria2_ID = unbox(reader.["Criteria2_ID"])
               Criteria3_ID = unbox(reader.["Criteria3_ID"])
               }
         }

// Sequence transformation

let UserBase = GetUsers |> Seq.toList

// Creating the matrix

let matrixUA =
    Matrix.ofList
        [ // Create list containing rows from the database
        for row in UserBase do
      // For each row, return list of columns (float values)
            yield [ float row.Criteria0_ID; 
                    float row.Criteria1_ID;
                    float row.Criteria2_ID;
                    float row.Criteria3_ID;
                                    ] ]

matrixUA

2 个答案:

答案 0 :(得分:3)

使用FsSql你可以这样写:

let readMatrixUA() =
    let connStr = SqlConnectionStringBuilder(DataSource="localhost\sqlexpress", IntegratedSecurity=true, InitialCatalog="TestExtractionF#")
    use cnn = new SqlConnection(connStr.ConnectionString)
    cnn.Open()
    Sql.execReader (Sql.withConnection cnn) "select * from SyntheseTest" []
    |> Sql.map Sql.asNameValue
    |> Seq.map (Seq.map (snd >> Option.fromDBNull >> Option.getOrDefault >> float))
    |> Matrix.ofSeq

答案 1 :(得分:1)

在当前版本的F#中,您始终需要自己定义user类型。你可以做一些技巧,使复制更好。最简单的方法是使用?运算符来获取以下语法:

let (?) (reader:SqlDataReader) (name:string) : 'T =
  unbox (reader.[name])

 yield { Criteria1_ID = reader?Criteria1_ID
         Criteria2_ID = reader?Criteria2_ID 
         Criteria3_ID = reader?Criteria3_ID }

您可以更进一步 - 如果您打开Microsoft.FSharp.Reflection,您可以使用FSharpType.GetRecordFields获取字段的名称(使用反射)并动态进行复制 - 如果您使用此方法,你只需要改变记录声明。对于当前版本的F#,这可能就此而言。

但是,F#3.0(来自Visual Studio 11)包含一个名为 type provders 的功能,它实质上允许您自动导入架构。您可以通过Don Syme(见for example this)和MSDN (draft) documentation的会谈了解更多信息。