演练:使用类型提供程序和实体访问 SQL 数据库 (F#)

F# 的 3.0 演练展示如何访问类型化数据是根据 ADO.NET 实体数据模型的 SQL 数据库。 本演练向您展示如何设置 F# SqlEntityConnection 类型提供程序与 SQL 数据库的使用、编写查询数据、如何对该数据库的存储过程,以及如何使用某些 ADO.NET Entity Framework 类型和方法更新数据库。

本演练演示以下任务,您应该按该演练的顺序执行才能成功:

  • 创建 School 数据库.

  • 创建和配置 F# 项目.

  • 配置类型提供程序和连接到实体数据模型.

  • 查询数据库.

  • 更新数据库

系统必备

您必须具备对运行可创建数据库的 SQL 服务器的访问权限,以便完成这些步骤。

创建 School 数据库

您可以在运行您具有管理访问权限,或您可以使用 LocalDB 的 SQL 服务器的任何服务器创建 School 数据库。

创建 School 数据库

  1. 在**“服务器资源管理器”中,打开快捷菜单“数据连接”节点,然后选择“添加链接”**。

    即会出现**“添加连接”**对话框。

  2. 在**“服务器名称”**框中,指定您具有管理权限的 SQL Server 的示例名称,或者,如果您无法访问服务器指定 (localdb \ v11.0)。

    SQL Server Express LocalDB 用于开发提供一个轻量数据库服务器和测试的计算机。 有关 LocalDB 的更多信息,请参见 演练:创建 LocalDB 数据库

    新节点在**“数据连接”下的“服务器资源管理器”**中创建。

  3. 打开新的连接节点的快捷菜单,然后选择**“新建查询”**。

  4. 在 Microsoft 网站上,打开创建 School 示例数据库,然后复制并粘贴将 Student 数据库创建到编辑器窗口的数据库脚本。

    在本演练中的下一步骤是根据以下教程:ADO.NET Entity Data Model Quickstart

创建和配置 F# 项目

在此步骤中,创建项目并将它设置为可以使用类型提供程序。

如何创建和配置 F# 项目。

  1. 关闭前一个项目,创建一个名为 SchoolEDM 的项目。

  2. 在**“解决方案资源管理器”中,打开“引用”的快捷菜单,然后选择“添加引用”**。

  3. 选择**“结构”节点,然后,在“结构”**列表中,选择 System.Data、 System.Data.Entity 和 System.Data.Linq

  4. 选择**“扩展”节点,添加引用到 FSharp.Data.TypeProviders 程序集,然后选择“确定”**按钮以关闭对话框。

  5. 添加以下代码以定义一个内部模块并打开相应的命名空间。 该类型提供程序只能插入类型到私有的或内部的命名空间。

    module internal SchoolEDM
    
    open System.Data.Linq
    open System.Data.Entity
    open Microsoft.FSharp.Data.TypeProviders
    
  6. 若要以交互方式在本演练中将代码作为脚本(而不是编译程序)运行,请打开项目节点的快捷菜单,选择**“添加新项目”**,添加 F# 脚本文件,然后将每个步骤中将该代码添加到脚本中。 若要加载程序集引用,请添加以下行。

    #r "System.Data.Entity.dll"
    #r "FSharp.Data.TypeProviders.dll"
    #r "System.Data.Linq.dll"
    
  7. 您可以在添加各代码块时突出显示之,并选择 Alt + Enter 键在 F# Interactive 中运行它。

配置类型提供程序和连接到实体数据模型

在此步骤中,您将使用数据连接设置类型提供程序并获取允许处理数据的数据上下文。

配置类型提供程序和连接到实体数据模型

  1. 输入以下代码来配置生成基于先前创建的实体数据模型的 F# 类型的 SqlEntityConnection 类型提供程序。 请只使用 SQL 连接字符串,而不是完全 EDMX 连接字符串。

    type private EntityConnection = SqlEntityConnection<ConnectionString="Server=SERVER\InstanceName;Initial Catalog=School;Integrated Security=SSPI;MultipleActiveResultSets=true",
                                                        Pluralize = true>
     >
    

    此操作设置类型提供程序与您先前创建的数据库连接。 属性 MultipleActiveResultSets 是必需的,当您使用 ADO.NET Entity Framework 时,因为此属性在连接的数据库允许多个命令执行异步,在 ADO.NET Entity Framework 代码中可能会经常发生。 有关详细信息,请参见 Multiple Active Result Sets (MARS)

  2. 获取数据上下文,该上下文为一对象,该对象包含作为属性和数据库存储的程序和函数的库表。

    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)
    

更新数据库

若要更新数据库,请使用实体框架类和方法。 您可以使用具有 SQLEntityConnection 类型提供程序的两种类型的数据上下文。 首先,ServiceTypes.SimpleDataContextTypes.EntityContainer 是简化的数据上下文,只包括表示数据库表和列的提供的属性。 其次,完整的数据上下文是实体框架类 ObjectContext 的实例,其中包含方法 AddObject 以便将行添加到数据库。 实体框架识别表及其相互关系,因此,它强制数据库一致性。

更新数据库

  1. 将下面的代码添加到程序中。 在本示例中,使用两个对象之间的关系来添加它们,并添加教师和办公室分配。 表 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 前,未在数据库中做任何更改。

  2. 现在,删除您添加的对象,以将数据库还原到其先前的状态。

    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#)

其他资源

类型提供程序

ADO.NET Entity Framework

.edmx File Overview (Entity Framework)

Edm Generator (EdmGen.exe)