逐步解說:使用類型提供者和實體存取 SQL 資料庫 (F#)
這個 F# 3.0 的逐步解說將示範如何根據 ADO.NET 實體資料模型,存取 SQL 資料庫中具類型的資料。 這個逐步解說將示範如何設定 SqlEntityConnection F# 類型提供者搭配 SQL 資料庫使用、如何撰寫對資料的查詢、如何在資料庫上呼叫預存程序,以及如何使用某些 ADO.NET Entity Framework 類型和方法更新資料庫。
這個逐步解說將說明下列工作,您應該按照這個逐步解說的順序執行才能成功:
建立 School 資料庫。
建立並設定 F# 專案。
設定類型提供者並連接至實體資料模型。
查詢資料庫。
更新資料庫
必要條件
您必須能夠存取執行 SQL Server 且可讓您建立資料庫的伺服器,才能完成這些步驟。
建立 School 資料庫
您可以在任何您具有系統管理存取權限且執行 SQL Server 的伺服器上建立 School 資料庫,或者您也可以使用 LocalDB。
若要建立 School 資料庫
在 [伺服器總管] 中,開啟 [資料連接] 節點的捷徑功能表,然後選擇 [加入連接]。
[加入連接] 對話方塊隨即出現。
在 [伺服器名稱] 方塊中,指定您具有系統管理存取權限之 SQL Server 執行個體的名稱,如果您沒有存取伺服器的權限,則指定 (localdb\v11.0)。
SQL Server Express LocalDB 提供輕量型的資料庫伺服器,可讓您在電腦上進行開發和測試時使用。 如需 LocalDB 的詳細資訊,請參閱逐步解說:在 Visual Studio 中建立本機資料庫檔案。
新節點已在 [伺服器總管] 的 [資料連接] 底下建立。
開啟新連接節點的捷徑功能表,然後選擇 [新增查詢]。
開啟 Microsoft 網站上的建立 School 範例資料庫 (Entity Framework 快速入門),然後複製建立 Student 資料庫的資料庫指令碼,並貼入編輯器視窗。
建立並設定 F# 專案
在這個步驟中,您會建立專案並將進行設定,以便使用類型提供者。
若要建立和設定 F# 專案
關閉先前的專案,建立另一個專案,並將它命名為 SchoolEDM。
在 [方案總管] 中開啟 [參考] 的捷徑功能表,然後選擇 [加入參考]。
選擇 [架構] 節點,然後在 [架構] 清單中選擇 [System.Data]、[System.Data.Entity] 以及 [System.Data.Linq]。
選擇 [擴充功能] 節點,加入 FSharp.Data.TypeProviders 組件的參考,然後選擇 [確定] 按鈕關閉對話方塊。
加入下列程式碼可定義內部模組並開啟適當的命名空間。 類型提供者只能將類型插入私用或內部命名空間。
module internal SchoolEDM open System.Data.Linq open System.Data.Entity open Microsoft.FSharp.Data.TypeProviders
若要以互動方式將這個逐步解說中的程式碼當做指令碼執行,而不是當做編譯的程式執行,請開啟專案節點的捷徑功能表,選擇 [加入新項目],加入 F# 指令碼檔,然後在每個步驟中將程式碼加入至指令碼。 若要載入組件參考,請加入下列各行。
#r "System.Data.Entity.dll" #r "FSharp.Data.TypeProviders.dll" #r "System.Data.Linq.dll"
在加入時反白顯示您加入的每一個程式碼區塊,然後選擇 Alt + Enter 鍵以 F# Interactive 執行。
設定類型提供者並連接至實體資料模型
在這個步驟中,您將設定具有資料連接的類型提供者,並且取得可讓您使用資料的資料內容。
若要設定類型提供者並連接至實體資料模型
輸入下列程式碼,依據您先前所建立的實體資料模型設定產生 F# 類型的 SqlEntityConnection 類型提供者。 僅使用 SQL 連接字串,而非完整的 EDMX 連接字串。
type private EntityConnection = SqlEntityConnection<ConnectionString="Server=SERVER\InstanceName;Initial Catalog=School;Integrated Security=SSPI;MultipleActiveResultSets=true", Pluralize = true> >
這個動作會設定具有您先前所建立資料庫連接的類型提供者。 當您使用 ADO.NET Entity Framework 時,會需要 MultipleActiveResultSets 屬性,因為這個屬性允許在單一連接中,於資料庫上以非同步方式執行多個命令,這種情況在 ADO.NET Entity Framework 程式碼中經常出現。 如需詳細資訊,請參閱 Multiple Active Result Sets (MARS)。
取得資料內容,這個物件包含做為屬性的資料庫資料表,以及做為方法的資料庫預存程序和函式。
let context = EntityConnection.GetDataContext()
查詢資料庫
在這個步驟中,您將使用 F# 查詢運算式在資料庫上執行各種查詢。
若要查詢資料
輸入下列程式碼可查詢實體資料模型中的資料。 請注意 Pluralize = true 的效果,它會將資料庫資料表 Course 變更為 Courses 以及 Person 變更為 People。
query { for course in context.Courses do select course } |> Seq.iter (fun course -> printfn "%s" course.Title) query { for person in context.People do select person } |> Seq.iter (fun person -> printfn "%s %s" person.FirstName person.LastName) // Add a where clause to filter results. query { for course in context.Courses do where (course.DepartmentID = 1) select course } |> Seq.iter (fun course -> printfn "%s" course.Title) // Join two tables. query { for course in context.Courses do join dept in context.Departments on (course.DepartmentID = dept.DepartmentID) select (course, dept.Name) } |> Seq.iter (fun (course, deptName) -> printfn "%s %s" course.Title deptName)
更新資料庫
若要更新資料庫,您可以使用 Entity Framework 類別和方法。 您可以使用兩種類型的資料內容搭配 SQLEntityConnection 類型提供者。 第一種是 ServiceTypes.SimpleDataContextTypes.EntityContainer,這是簡化的資料內容,只包含代表資料庫資料表和資料行的所提供屬性。 第二種是完整資料內容,這是 Entity Framework 類別 ObjectContext 的執行個體,其中包含將資料列加入至資料庫的 AddObject 方法。 Entity Framework 可辨識資料表和資料表之間的關聯性,因此會強制資料庫的一致性。
若要更新資料庫
將下列程式碼加入您的程式中。 在這個範例中,您會加入兩個彼此之間具有關聯性的物件,而且會加入一位講師和一份辦公室工作。 資料表 OfficeAssignments 包含 InstructorID 資料行,該資料行參考 Person 資料表中的 PersonID 資料行。
// The full data context let fullContext = context.DataContext // A helper function. let nullable value = new System.Nullable<_>(value) let addInstructor(lastName, firstName, hireDate, office) = let hireDate = DateTime.Parse(hireDate) let newPerson = new EntityConnection.ServiceTypes.Person(LastName = lastName, FirstName = firstName, HireDate = nullable hireDate) fullContext.AddObject("People", newPerson) let newOffice = new EntityConnection.ServiceTypes.OfficeAssignment(Location = office) fullContext.AddObject("OfficeAssignments", newOffice) fullContext.CommandTimeout <- nullable 1000 fullContext.SaveChanges() |> printfn "Saved changes: %d object(s) modified." addInstructor("Parker", "Darren", "1/1/1998", "41/3720")
在您呼叫 SaveChanges 之前,資料庫中不會有任何變更。
現在將您加入的物件刪除,藉此將資料庫還原至先前的狀態。
let deleteInstructor(lastName, firstName) = query { for person in context.People do where (person.FirstName = firstName && person.LastName = lastName) select person } |> Seq.iter (fun person-> query { for officeAssignment in context.OfficeAssignments do where (officeAssignment.Person.PersonID = person.PersonID) select officeAssignment } |> Seq.iter (fun officeAssignment -> fullContext.DeleteObject(officeAssignment)) fullContext.DeleteObject(person)) // The call to SaveChanges should be outside of any iteration on the queries. fullContext.SaveChanges() |> printfn "Saved changed: %d object(s) modified." deleteInstructor("Parker", "Darren")
警告
當您使用查詢運算式時,必須記住查詢受到延遲評估限制。因此,資料庫在任何鏈結評估期間仍會保持開啟可供讀取,例如在 Lambda 運算式區塊中的每一個查詢運算式之後。所有資料庫作業無論是明確或隱含使用交易,都必須在讀取作業完成之後發生。
後續步驟
您可以檢閱查詢運算式 (F#) 中提供的查詢運算子,藉此探索其他查詢選項,也可以檢閱 ADO.NET Entity Framework,了解當您使用這個類型提供者時有哪些功能可以使用。
請參閱
工作
逐步解說:從 EDMX 結構描述檔案產生 F# 類型 (F#)
參考
SqlEntityConnection 類型提供者 (F#)