使用 Entity Framework 4.0 Database First 和 ASP.NET 4 Web Forms 入门 - 第 7 部分

作者 :Tom Dykstra

Contoso University 示例 Web 应用程序演示如何使用 Entity Framework 4.0 和 Visual Studio 2010 创建 ASP.NET Web Forms应用程序。 有关教程系列的信息,请参阅 系列中的第一个教程

使用存储过程

在上一教程中,你实现了每个层次结构的表继承模式。 本教程介绍如何使用存储过程来更好地控制数据库访问。

实体框架允许你指定它应使用存储过程进行数据库访问。 对于任何实体类型,可以指定用于创建、更新或删除该类型的实体的存储过程。 然后,在数据模型中,可以添加对存储过程的引用,这些存储过程可用于执行检索实体集等任务。

使用存储过程是数据库访问的常见要求。 在某些情况下,出于安全原因,数据库管理员可能要求所有数据库访问都经过存储过程。 在其他情况下,你可能希望将业务逻辑构建到实体框架在更新数据库时使用的一些流程中。 例如,每当删除实体时,你都可能需要将其复制到存档数据库。 或者,每当更新行时,你可能想要将一行写入日志记录表,以记录更改者。 可以在实体框架删除实体或更新实体时调用的存储过程中执行这些类型的任务。

与上一教程一样,不会创建任何新页面。 相反,你将更改实体框架访问已创建的某些页面的数据库的方式。

在本教程中,你将在数据库中创建用于插入 和 Instructor 实体的Student存储过程。 你将将它们添加到数据模型,并指定实体框架应使用它们向数据库添加 StudentInstructor 实体。 还将创建可用于检索 Course 实体的存储过程。

在数据库中创建存储过程

(如果使用本教程中可供下载的项目中的 School.mdf 文件,则可以跳过此部分,因为存储过程已存在。)

“服务器资源管理器”中,展开“ School.mdf”,右键单击“ 存储过程”,然后选择“ 添加新存储过程”。

image15

复制以下 SQL 语句并将其粘贴到存储过程窗口中,替换主干存储过程。

CREATE PROCEDURE [dbo].[InsertStudent]
    @LastName nvarchar(50),
    @FirstName nvarchar(50),
    @EnrollmentDate datetime
    AS
    INSERT INTO dbo.Person (LastName, 
                FirstName, 
                EnrollmentDate)
    VALUES (@LastName, 
        @FirstName, 
        @EnrollmentDate);
    SELECT SCOPE_IDENTITY() as NewPersonID;

image14

Student实体具有四个属性:PersonIDFirstNameLastName、 和 EnrollmentDate。 数据库自动生成 ID 值,存储过程接受其他三个参数。 存储过程返回新行的记录键的值,以便实体框架可以在它保留在内存中的实体版本中跟踪该值。

保存并关闭存储过程窗口。

InsertInstructor使用以下 SQL 语句以相同的方式创建存储过程:

CREATE PROCEDURE [dbo].[InsertInstructor]
        @LastName nvarchar(50),
    @FirstName nvarchar(50),
    @HireDate datetime
    AS
    INSERT INTO dbo.Person (LastName, 
                FirstName, 
                HireDate)
    VALUES (@LastName, 
        @FirstName, 
        @HireDate);
    SELECT SCOPE_IDENTITY() as NewPersonID;

还为 StudentInstructor 实体创建Update存储过程。 (数据库已有适用于 DeletePersonStudent entities 的存储过程Instructor。)

CREATE PROCEDURE [dbo].[UpdateStudent]
    @PersonID int,
    @LastName nvarchar(50),
    @FirstName nvarchar(50),
    @EnrollmentDate datetime
    AS
    UPDATE Person SET LastName=@LastName, 
            FirstName=@FirstName,
            EnrollmentDate=@EnrollmentDate
    WHERE PersonID=@PersonID;
CREATE PROCEDURE [dbo].[UpdateInstructor]
    @PersonID int,
    @LastName nvarchar(50),
    @FirstName nvarchar(50),
    @HireDate datetime
    AS
    UPDATE Person SET LastName=@LastName, 
            FirstName=@FirstName,
            HireDate=@HireDate
    WHERE PersonID=@PersonID;

在本教程中,你将为每个实体类型映射所有三个函数(插入、更新和删除)。 实体框架版本 4 允许仅将其中一个或两个函数映射到存储过程,而不映射其他函数,但有一个例外:如果映射 update 函数而不是 delete 函数,则在尝试删除实体时实体框架将引发异常。 在 Entity Framework 版本 3.5 中,映射存储过程的灵活性不大:如果映射一个函数,则需要映射所有三个函数。

若要创建读取而不是更新数据的存储过程,请使用以下 SQL 语句创建一个选择所有 Course 实体的存储过程:

CREATE PROCEDURE [dbo].[GetCourses]
            AS
            SELECT CourseID, Title, Credits, DepartmentID FROM dbo.Course

将存储过程添加到数据模型

存储过程现已在数据库中定义,但它们必须添加到数据模型中,才能使其可用于实体框架。 打开 SchoolModel.edmx,右键单击设计图面,然后选择“ 从数据库更新模型”。 在“选择数据库对象”对话框的“添加”选项卡中,展开“存储过程”,选择新创建的存储过程和DeletePerson存储过程,然后单击“完成”。

image20

映射存储过程

在数据模型设计器中,右键单击实体并选择 Student存储过程映射”。

image21

此时将显示 “映射详细信息” 窗口,可在其中指定实体框架应用于插入、更新和删除此类型的实体的存储过程。

image22

Insert 函数设置为 InsertStudent。 该窗口显示存储过程参数的列表,其中每个参数都必须映射到实体属性。 其中两个是自动映射的,因为名称相同。 没有名为 FirstName的实体属性,因此必须手动从显示可用实体属性的下拉列表中进行选择 FirstMidName 。 (这是因为在第FirstNameFirstMidName一个 tutorial.)

image23

在同一“ 映射详细信息” 窗口中,将 Update 函数映射到 UpdateStudent 存储过程 (确保将 指定 FirstMidName 为 的参数 FirstName值,就像对 Insert 存储过程) 将 Delete 函数指定为 DeletePerson 存储过程。

image01

按照相同的过程将讲师的插入、更新和删除存储过程映射到 Instructor 实体。

image02

对于读取而不是更新数据的存储过程,可以使用 “模型浏览器 ”窗口将存储过程映射到它返回的实体类型。 在数据模型设计器中,右键单击设计图面并选择“ 模型浏览器”。 打开 “SchoolModel.Store ”节点,然后打开“ 存储过程” 节点。 然后右键单击存储过程并选择 GetCourses添加函数导入”。

image24

“添加函数导入 ”对话框中的“ 返回集合 ”下,选择“ 实体Course ,然后选择作为返回的实体类型。 完成后,单击“确定”。 保存并关闭 .edmx 文件。

image25

使用插入、更新和删除存储过程

将插入、更新和删除数据的存储过程添加到数据模型并将其映射到相应的实体后,实体框架会自动使用这些存储过程。 现在可以运行 StudentsAdd.aspx 页,每次创建新学生时,实体框架将使用 InsertStudent 存储过程将新行添加到 Student 表中。

image03

运行 Students.aspx 页,新学生将显示在列表中。

image04

更改名称以验证更新函数是否正常工作,然后删除学生以验证删除函数是否正常工作。

image05

使用选择存储过程

实体框架不会自动运行存储过程(如 GetCourses),并且不能将它们与 控件一起使用 EntityDataSource 。 若要使用它们,请通过代码调用它们。

打开 InstructorsCourses.aspx.cs 文件。 方法 PopulateDropDownLists 使用 LINQ-to-Entities 查询来检索所有课程实体,以便它可以循环访问列表并确定将讲师分配到哪些实体以及未分配哪些实体:

var allCourses = (from c in context.Courses
                  select c).ToList();

将此代码替换为以下代码:

var allCourses = context.GetCourses();

页面现在使用 GetCourses 存储过程检索所有课程的列表。 运行页面以验证它是否像以前一样工作。

(存储过程检索的实体的导航属性可能不会自动填充与这些实体相关的数据,具体取决于 ObjectContext 默认设置。有关详细信息,请参阅在 MSDN Library 中 加载相关对象 。)

在下一教程中,你将了解如何使用动态数据功能更轻松地编程和测试数据格式设置和验证规则。 可以在数据模型元数据中指定此类规则,并且这些规则会自动应用于每个页面,例如数据格式字符串以及是否需要字段。