F#LINQ类型适合一体

时间:2012-01-28 21:00:29

标签: linq linq-to-sql f#

我正在使用F#3.0学习LINQ。我想知道如何将我的旧类转换为在F#3.0中使用新的LINQ功能 例如,我在SQL Server 2008 R2中创建了一个简单的数据表,数据库名称是myDatabase。

-- Create the Table1 table.
CREATE TABLE [dbo].[Table1] (
    [Id]        INT        NOT NULL,
    [TestData1] INT        NOT NULL,
    [TestData2] FLOAT (53) NOT NULL,
    [Name]      NTEXT      NOT NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);
USE MyDatabase

INSERT INTO Table1 (Id, TestData1, TestData2, Name)
VALUES(1, 10, 5.5, 'Testing1');
INSERT INTO Table1 (Id, TestData1, TestData2, Name)
VALUES(2, 20, -1.2, 'Testing2');

对于F#2.0,我可以创建一个小类来从Table1中检索数据并返回主程序。

#light
module myData
open System
open System.Collections.Generic 
open System.Data
open System.Data.SqlClient

type getData(tableName: string) = class
    let sqlConn = "server=(local); Integrated Security=True; Database=MyDatabase"
    let connDB = new SqlConnection(sqlConn)

    let sqlByFun (cmdText,  unwrapping) =
        use cmd = new SqlCommand(cmdText, connDB)
        let reader = cmd.ExecuteReader()
        seq { while reader.Read() do
              yield unwrapping(reader) }

    let dbTable1(tableName: string) =
        let sql = "SELECT Id, TestData1, TestData2, Name FROM Table1 ORDER BY Id"
        connDB.Open()
        let data = sqlByFun(sqlChanges, (fun reader -> 
                           (reader.GetInt32(0),  reader.GetInt32(1), 
                           reader.GetDecimal(2),reader.GetString(3)))) 
                 |> Seq.toArray
        connDB.Close()
        data 

    member this.getTable(table1) = dbTable1(table1)

然后在我的主程序中:program.fs,我可以使用myData的类:

#light
open myData
open System
open System.Collections.Generic 
open System.Data
open System.Data.SqlClient

let db = new myData.getData("Table1")
let table1Data = db.getTable("Table1")
printfn "Done"

现在,使用F#3.0和LINQ,我可以像这样重写这个类:

#light
open System
open System.Data
open System.Data.SqlClient
open System.Data.Linq
open Microsoft.FSharp.Data.TypeProviders
open Microsoft.FSharp.Linq

[<Generate>]
type dbSchema = SqlDataConnection<"Data Source=.;Initial Catalog=MyDatabase;Integrated Security=True">
let db = dbSchema.GetDataContext()
let dbTable1(tableName: string) =
    let data =
        query {
              for row in db.Table1 do
              sortBy row.Id
              select (row.Id, row.TestData1, row.TestData2, row.Name)
              }
    data

我可以看到这部分,代码更简洁,更清晰,但我希望它在一个类中,可以从我的主程序中调用。 如何将LINQ代码放在类中并由主程序使用? 谢谢, 约翰

1 个答案:

答案 0 :(得分:3)

从你的问题来看,你想要实现的目标并不完全清楚。在您的示例中,您的新课程(以及方法)会使用tableName参数,但无论如何您总是从Table1读取数据。

编写由表名参数化的LINQ代码并不容易,因为不同的表可能有不同的列,因此您不能使用相同的类型来访问它们。如果您有不同的表具有相同的结构,那么您可以将它们合并到一个表中,并添加一个额外的列来区分记录。如果要访问不同的表,则需要为每个表编写不同的查询。

关于类中的封装,您可以在F#3.0中轻松完成:

// Global declarations for SQL type provider
[<Literal>]
let connStr = "Data Source=.;Initial Catalog=MyDatabase;Integrated Security=True"
[<Generate>] 
type dbSchema = SqlDataConnection<connStr> 

// Declaration of a class that exposes data access functionality
type DataAccess() =
  // Note: You can pass different connection string to 'GetDataContext'
  // if you want to keep connection string in config file instead of in code.
  let db = dbSchema.GetDataContext() 

  /// Reads data from Table1
  member x.LoadTable1() =
    query { for row in db.Table1 do 
            sortBy row.Id 
            select (row.Id, row.TestData1, row.TestData2, row.Name) }