2012-01-28 25 views
0

我正在學習LINQ與F#3.0。我想知道如何將我的舊類轉換爲在F#3.0中使用新的LINQ功能。 例如,我在SQL Server 2008 R2中創建了一個簡單的數據表,數據庫名稱爲myDatabase。F#LINQ類型適合一個

-- 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代碼放到一個類中並由主程序使用? 謝謝, 約翰

回答

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) } 
+0

嗨,托馬斯: 非常感謝你。我必須查詢大約10個數據表,table1只是一個簡單的表格供我的例子使用。由於我有這麼多的數據表來查詢,所以我把所有數據庫查詢放到一個類中,然後從主程序中調用它。但是在使用LINQ之後,我不知道如何將所有數據庫查詢放到一個類中,因此我問。 – 2012-01-29 10:12:25

+0

如果我想讓連接字符串成爲DataAccess類的參數,該怎麼辦? – 2012-10-28 09:08:58