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

此针对 F# 3.0 的演练演示如何根据 ADO.NET 实体数据模型访问 SQL 数据库的类型化数据。 此演练演示如何设置 F# SqlEntityConnection 类型提供程序以将其与 SQL 数据库一起使用、如何针对数据编写查询、如何对数据库调用存储过程以及如何使用某些 ADO.NET Entity Framework 类型和方法来更新数据库。

此演练演示了下列任务,你应按以下顺序执行这些任务才能成功完成演练:

  • 创建 School 数据库。

  • 创建并配置 F# 项目。

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

  • 查询数据库。

  • 更新数据库

系统必备

你必须能够访问正在运行可从中创建数据库的 SQL Server 的服务器才能完成这些步骤。

创建 School 数据库

你可以在正在运行你对其具有管理访问权的 SQL Server 的任何服务器上创建 School 数据库,也可使用 LocalDB。

创建 School 数据库

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

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

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

    SQL Server Express LocalDB 提供了轻型数据库服务器以便在你的计算机上进行开发和测试。 有关 LocalDB 的更多信息,请参见演练:在 Visual Studio 中创建本地数据库文件

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

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

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

创建并配置 F# 项目

在此步骤中,你将创建一个项目并将其设置为使用类型提供程序。

创建并配置 F# 项目

  1. 关闭前一个项目并创建另一个项目,然后将其命名为 SchoolEDM。

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

  3. 选择**“框架”节点,然后在“框架”**列表中,选择 System.DataSystem.Data.EntitySystem.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. 输入以下代码来配置 SqlEntityConnection 类型提供程序,该提供程序根据你之前创建的实体数据模型来生成 F# 类型。 仅使用 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 代码中经常出现。 有关详细信息,请参阅多个活动结果集 (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)
    

更新数据库

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

更新数据库

  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 实体框架 以了解在使用此类型提供程序时可用的功能。

请参见

任务

演练:根据 EDMX 架构文件生成 F# 类型 (F#)

参考

SqlEntityConnection 类型提供程序 (F#)

EDM 生成器 (EdmGen.exe)

概念

ADO.NET 实体框架

其他资源

类型提供程序

.edmx File Overview (Entity Framework)