演练:将实体映射到存储过程

本主题演示如何使用 ADO.NET 实体数据模型设计器(实体设计器)将实体类型的插入、更新和删除操作映射到存储过程。实体类型的插入、更新和删除操作可以使用系统自动生成的 SQL 语句(默认),也可以使用开发人员所指定的存储过程。无论是否使用存储过程来更新数据库,用于创建、更新和删除实体的应用程序代码都是一样的。

在本演练中,将通过修改 CourseManager 应用程序中所用的实体数据模型 (EDM),将两个实体类型映射到存储过程(有关更多信息,请参见本主题后面的“系统必备”一节)。此外,还将编写用于插入、更新和删除实体类型的代码。

系统必备

要完成本演练,必须生成 CourseManager 应用程序。有关更多信息和说明,请参见实体框架快速入门。生成该应用程序后,将通过把两个实体类型映射到存储过程来修改其 EDM。

Note注意

因为本文档中的许多演练主题都使用该 CourseManager 应用程序作为起点,所以建议在本演练中使用 CourseManager 应用程序的副本,而不要编辑原始 CourseManager 代码。

本演练假定读者具备 Visual Studio、.NET Framework 的基本知识,并能使用 Visual C# 或 Visual Basic 进行编程。

将 Person 实体映射到存储过程

将实体的插入操作映射到存储过程时,如果服务器为插入的行创建主键值,则必须将该值映射回实体的键属性。在本示例中,InsertPerson 存储过程返回新创建的主键,作为存储过程的结果集的一部分。主键是使用实体设计器的**“<添加结果绑定>”**功能映射到实体键 (PersonID) 的。

将 Person 实体映射到存储过程

  1. 在 Visual Studio 中打开 CourseManager 解决方案。

  2. 在解决方案资源管理器中,双击 School.edmx 文件。

    该 School.edmx 文件将在 ADO.NET 实体数据模型设计器(实体设计器)中打开。

  3. 右键单击 Person 实体类型并选择**“存储过程映射”[Stored Procedure Mapping]**。

    存储过程映射将显示在**“映射详细信息”**窗口中。

  4. 单击**“<选择插入函数>”**。

    该字段即成为一个下拉列表,其中显示 EDM 中包含的存储过程。

  5. 从下拉列表中选择 InsertPerson

    此时将显示存储过程参数和实体属性之间的默认映射。请注意,箭头指示映射方向:属性值是提供给存储过程参数的。

  6. 单击**“<添加结果绑定>”**。

    该字段即变为可编辑状态。

  7. InsertPerson 存储过程返回的参数的名称 NewPersonID 替换**“<添加结果绑定>”。按“Enter”**。

    默认情况下,NewPersonID 映射到实体键 PersonID。请注意,箭头指示映射方向:结果列的值是提供给属性的。

  8. 单击**“<选择更新函数>”**,然后从产生的下拉列表中选择 UpdatePerson

    此时将显示存储过程参数和实体属性之间的默认映射。

  9. 单击**“<选择删除函数>”**,然后从产生的下拉列表中选择 DeletePerson

    此时将显示存储过程参数和实体属性之间的默认映射。

现在,Person 实体类型的插入、更新和删除操作即映射到存储过程。

将 OfficeAssignment 实体映射到存储过程

如果将一对一关联某一端的实体类型映射到存储过程,则必须将该关联另一端的实体也映射到存储过程。在本示例中,我们将 OfficeAssignment 实体类型映射到存储过程,因为它和 Person 实体类型具有一对一关联。在此映射中,我们在更新操作中使用**“使用原始值”**选项,以便能够方便地检查应用程序代码中的并发。

将 OfficeAssignment 实体映射到存储过程

  1. 右键单击 OfficeAssignment 实体类型并选择 Stored Procedure Mapping

    存储过程映射将显示在**“映射详细信息”**窗口中。

  2. 单击**“<选择插入函数>”**,然后从产生的下拉列表中选择 InsertOfficeAssignment

    此时将显示存储过程参数和实体属性之间的默认映射。

  3. 单击**“<添加结果绑定>”**。

    该字段即变为可编辑状态。

  4. 键入 Timestamp 代替**“<添加结果绑定>”**。

  5. 单击 Propery/Value 列中 Timestamp 旁的空字段。

    该字段即变为一个属性下拉列表,我们可将 InsertOfficeAssignment 存储过程所返回的值映射到其中的属性。

  6. 从下拉列表中选择 Timestamp

  7. 单击**“<选择更新函数>”**,然后从产生的下拉列表中选择 UpdateOfficeAssignment

    此时将显示存储过程参数和实体属性之间的默认映射。每个映射的属性旁的**“使用原始值”**列中都会显示复选框。

  8. 单击**“属性”**列中对应于 OrigTimestamp 参数的空字段,然后从产生的下拉列表中选择 Timestamp

    因为参数名与属性名不是完全匹配的,所以实体设计器不将它作为默认映射。

  9. 选中**“使用原始值”**列中对应于 Timestamp 属性的框。

    如果尝试更新,则向数据库写回数据时,将使用最初从数据库读取的 Timestamp 属性的值。如果值与数据库中的值不匹配,将引发 OptimisticConcurrencyException

  10. 单击**“<添加结果绑定>”**。

    该字段即变为可编辑状态。

  11. 将**“<添加结果绑定>”**替换为 Timestamp

  12. 单击 Propery/Value 列中 Timestamp 旁的空字段。

    该字段即变为一个属性下拉列表,我们可将 UpdateOfficeAssignment 存储过程所返回的结果列映射到其中的属性。

  13. 从下拉列表中选择 Timestamp

  14. 单击**“<选择删除函数>”**,然后从产生的下拉列表中选择 DeleteOfficeAssignment

    此时将显示存储过程参数和实体属性之间的默认映射。

现在,OfficeAssignment 实体类型的插入、更新和删除操作即映射到存储过程。

构造用户界面

接下来,将两个窗体添加到 CourseManager 应用程序中。一个窗体提供用于查看和更新教师信息的界面。另一个窗体提供用于查看和更新办公室分配的界面。

构造用户界面

  1. 在**“解决方案资源管理器”中右键单击 CourseManager 项目,指向“添加”,然后选择“新建项”**。

    出现**“添加新项”**对话框。

  2. 选择**“Windows 窗体”,将窗体名称设置为“InstructorViewer.vb”或“InstructorViewer.cs”,然后单击“添加”**。

    新窗体即被添加到项目中,并在窗体设计器中打开。窗体的名称设置为 InstructorViewer,文本设置为 InstructorViewer

  3. DataGridView 控件从工具箱拖动到窗体上,并在**“属性”窗口中将其“名称”**设置为 instructorGridView

  4. Button 控件从工具箱拖到窗体上。将其**“名称”设置为 updateInstructor,并将其“文本”**设置为 Update Instructor

  5. 将另一个 Button 控件从工具箱拖动到窗体上。将其**“名称”设置为 viewOffices,并将其“文本”**设置为 View Offices

  6. 在**“解决方案资源管理器”中右键单击 CourseManager 项目,指向“添加”,然后选择“新建项”**。

    出现**“添加新项”**对话框。

  7. 选择**“Windows 窗体”,将窗体名称设置为“OfficeViewer.vb”或“OfficeViewer.cs”,然后单击“添加”**。

    新窗体即被添加到项目中,并在窗体设计器中打开。窗体的名称设置为 OfficeViewer,文本设置为 OfficeViewer

  8. ComboBox 控件从工具箱拖动到窗体上,并将其**“名称”**设置为 instructorList

  9. TextBox 控件从工具箱拖动到窗体上,并将其**“名称”**设置为 officeLocation

  10. Button 控件从工具箱拖到窗体上。将其**“名称”设置为 updateOffice,并将其“文本”**设置为 Update Office

  11. 在**“解决方案资源管理器”**中,双击 CourseViewer.vbCourseViewer.cs

    出现 CourseViewer 窗体的设计视图。

  12. Button 控件从工具箱拖到窗体上。

  13. 在**“属性”窗口中,将 Button“名称”属性设置为 viewInstructors,并将“文本”**属性设置为 View Instructors

  14. 双击 viewInstructorsButton 控件。

    此时将打开 CourseViewer 窗体的代码隐藏文件。

  15. 将下面的代码添加到 viewInstructors_Click 事件处理程序中:

    Dim instructorViewer As New InstructorViewer()
    instructorViewer.Visible = True
    
    InstructorViewer instructorViewer = new InstructorViewer();
    instructorViewer.Visible = true;
    
  16. 返回到 InstructorViewer 窗体的设计视图。

  17. 双击 viewOfficesButton 控件。

    此时将打开 Form2 的代码隐藏文件。

  18. 将下面的代码添加到 viewOffices_Click 事件处理程序中:

    Dim officeViewer As New OfficeViewer()
    officeViewer.Visible = True
    
    OfficeViewer officeViewer = new OfficeViewer();
    officeViewer.Visible = true;
    

现在,就完成了用户界面。

查看和更新教师信息

在本过程中,将向 InstructorViewer 窗体添加一些代码,用于查看和更新教师信息。具体而言,这些代码执行以下操作:

  • DataGridView 绑定到用于返回 Person 类型为教师的相关信息的查询。有关将对象绑定到控件的更多信息,请参见将对象绑定到控件(实体框架)

  • DataGridView 控件中的任何更改(插入、更新或删除)保存到数据库。

  • updateInstructor_Click 事件处理程序中调用 SaveChanges() 时,使用先前映射的存储过程将数据写入数据库。

查看和更新教师信息

  1. 在窗体设计器中打开 InstructorViewer 窗体后,双击 InstructorViewer 窗体。

    此时将打开 InstructorViewer 窗体的代码隐藏文件。

  2. 添加下面的 using (C#) 或 Imports (Visual Basic) 语句:

    Imports System.Data.Objects
    Imports System.Data.Objects.DataClasses
    
    using System.Data.Objects;
    using System.Data.Objects.DataClasses;
    
  3. 向表示对象上下文的 InstructorViewer 类添加一个属性:

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities
    
    // Create an ObjectContext instance based on SchoolEntity.
    private SchoolEntities schoolContext;
    
  4. InstructorViewer_Load 事件处理程序中,添加代码以初始化对象上下文,并将 DataGridView 控件的数据源设置为用于返回所有不具有 nullHireDatePerson 类型的查询。

    ' Initialize the ObjectContext.
    schoolContext = New SchoolEntities()
    Dim instructorQuery As ObjectQuery(Of Person) = _
        schoolContext.Person.Include("OfficeAssignment") _
        .Where("it.HireDate is not null") _
        .OrderBy("it.LastName")
    instructorGridView.DataSource = instructorQuery _
        .Execute(MergeOption.OverwriteChanges)
    instructorGridView.Columns("EnrollmentDate").Visible = False
    
    // Initialize schoolContext.
    schoolContext = new SchoolEntities();
    
    // Define the query to retrieve instructors.
    ObjectQuery<Person> instructorQuery = schoolContext.Person
        .Include("OfficeAssignment")
        .Where("it.HireDate is not null")
        .OrderBy("it.LastName");
    
    // Execute and bind the instructorList control to the query.
    instructorGridView.DataSource = instructorQuery.
        Execute(MergeOption.OverwriteChanges);
    instructorGridView.Columns["EnrollmentDate"].Visible = false;
    
  5. 返回 InstructorViewer 窗体的设计视图,然后双击 updateInstructorButton 控件。

    updateInstructor_Click 事件处理程序即添加到代码隐藏文件。

  6. 将代码添加到 updateInstructor_Click 事件处理程序,用于保存在 instructorGridViewDataGridView 控件中对教师信息所做的所有更改。

    Dim numChanges As Integer
    ' Save object changes to the database, display a 
    ' message, and refresh the form.
    numChanges = schoolContext.SaveChanges()
    MessageBox.Show(numChanges.ToString() + _
        " change(s) saved to the database.")
    Me.Refresh()
    
    int numChanges;
    // Save object changes to the database, display a 
    // message, and refresh the form.
    numChanges = schoolContext.SaveChanges();
    MessageBox.Show(numChanges.ToString() +
        " change(s) saved to the database.");
    this.Refresh();
    

按 Ctrl+F5 运行应用程序。现在,通过单击 View Instructors,在显示的表中进行更改,然后单击 Update Instructor,即可查看和更新教师信息。

查看和更新办公室信息

在本过程中,将向 OfficeViewer 窗体添加一些代码,用于查看和更新办公室分配信息。具体而言,这些代码执行以下操作:

  • ComboBox 绑定到用于返回教师信息的查询。

  • TextBox 中显示所选教师的办公室位置信息。

  • updateOffice_Click 事件处理程序中调用 SaveChanges() 时,使用先前映射的存储过程将数据写入数据库。

查看和更新办公室信息

  1. 在窗体设计器中打开 OfficeViewer 窗体后,双击 OfficeViewer 窗体。

    此时将打开 OfficeViewer 窗体的代码隐藏文件。

  2. 添加下面的 using (C#) 或 Imports (Visual Basic) 语句:

    Imports System.Data.Objects
    Imports System.Data.Objects.DataClasses
    
    using System.Data.Objects;
    using System.Data.Objects.DataClasses;
    
  3. 向表示对象上下文的 OfficeViewer 类添加一个属性:

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities
    
    // Create an ObjectContext instance based on SchoolEntity.
    private SchoolEntities schoolContext;
    
  4. 将下面的方法添加到窗体:

    Private Sub ExecuteInstructorQuery()
        ' Define the query to retrieve instructors.
        Dim instructorQuery As ObjectQuery(Of Person) = _
            schoolContext.Person.Include("OfficeAssignment"). _
            Where("it.HireDate is not null").OrderBy("it.LastName")
    
        'Execute and bind the instructorList control to the query.
        'Using MergeOption.OverwriteChanges overwrites local data
        'with data from the database.
        instructorList.DataSource = instructorQuery _
            .Execute(MergeOption.OverwriteChanges)
        instructorList.DisplayMember = "LastName"
    End Sub
    
    private void ExecuteInstructorQuery()
    {
        // Define the query to retrieve instructors.
        ObjectQuery<Person> instructorQuery = schoolContext.Person
            .Include("OfficeAssignment")
            .Where("it.HireDate is not null")
            .OrderBy("it.LastName");
    
        //Execute and bind the instructorList control to the query.
        //Using MergeOption.OverwriteChanges overwrites local data
        //with data from the database.
        instructorList.DataSource = instructorQuery
            .Execute(MergeOption.OverwriteChanges);
        instructorList.DisplayMember = "LastName";
    }
    

    此方法执行一个查询,用于返回教师信息并将结果绑定到 instructorListComboBox 控件。

  5. OfficeViewer_Load 事件处理程序中,添加代码以初始化对象上下文,然后调用一个方法将 ComboBox 控件绑定到用于返回所有不具有 nullHireDatePerson 类型的查询。

    schoolContext = New SchoolEntities()
    ExecuteInstructorQuery()
    
    schoolContext = new SchoolEntities();
    ExecuteInstructorQuery();
    
  6. 返回 OfficeViewer 窗体的设计视图,然后双击 instructorListComboBox 控件。

    instructorList_SelectedIndexChanged 事件处理程序即添加到代码隐藏文件。

  7. 将代码添加到事件处理程序,用于在 ListBox 控件中显示所选教师的办公室位置,并禁用 updateOfficeButton 控件。对所选办公室位置进行更改后,将启用此控件。

    Dim instructor As Person = CType(Me.instructorList _
        .SelectedItem(), Person)
    
    If Not instructor.OfficeAssignment Is Nothing Then
        Me.officeLocation.Text = instructor _
            .OfficeAssignment.Location.ToString()
    Else
        Me.officeLocation.Text = ""
    End If
    
    ' Disable the updateOffice button until a change
    ' has been made to the office location.
    updateOffice.Enabled = False
    
    'forceChanges.Enabled = False
    
    Person instructor = (Person)this.instructorList.
        SelectedItem;
    
    if (instructor.OfficeAssignment != null)
    {
        this.officeLocation.Text = instructor.
            OfficeAssignment.Location.ToString();
    }
    else
    {
        this.officeLocation.Text = "";
    }
    
    // Disable the updateOffice button until a change
    // has been made to the office location.
    updateOffice.Enabled = false;
    
    //forceChanges.Enabled = false;
    
  8. 返回 OfficeViewer 窗体的设计视图,然后双击 updateOfficeButton 控件。

    updateOffice_Click 事件处理程序即添加到代码隐藏文件。

  9. 添加一些代码,用于保存在 officeLocationTextBox 控件中对办公室信息所做的所有更改:

    Try
        Dim numChanges As Integer
        Dim currentInstructor As Person = CType(Me.instructorList _
            .SelectedItem(), Person)
        If Me.officeLocation.Text <> String.Empty Then
            If Not currentInstructor.OfficeAssignment Is Nothing Then
                currentInstructor.OfficeAssignment.Location() = _
                    Me.officeLocation.Text
            Else
                Dim temp(8) As Byte
                currentInstructor.OfficeAssignment = _
                    OfficeAssignment.CreateOfficeAssignment( _
                    currentInstructor.PersonID, _
                    Me.officeLocation.Text, temp)
            End If
        Else
            schoolContext.DeleteObject(currentInstructor. _
                                       OfficeAssignment)
        End If
        numChanges = schoolContext.SaveChanges()
        MessageBox.Show(numChanges.ToString() _
                + " change(s) saved to the database.")
    Catch oce As OptimisticConcurrencyException
        MessageBox.Show(oce.Message + " The conflict " & _
                "occurred on " & oce.StateEntries(0).Entity _
                .ToString() & "with key value " & _
                oce.StateEntries(0).EntityKey.EntityKeyValues(0) _
                .Value)
    
        'forceChanges.Enabled = True
    Catch ue As UpdateException
        MessageBox.Show(ue.Message & " Click OK to retrieve " _
                & "the latest data from the database.")
        ExecuteInstructorQuery()
        Me.Refresh()
    Finally
        ' Disable the updateOffice button until another
        ' change has been made to the location.
        updateOffice.Enabled = False
    End Try
    
    try
    {
        int numChanges;
        Person currentInstructor = (Person)this.instructorList.
            SelectedItem;
        if (this.officeLocation.Text != string.Empty)
        {
            if (currentInstructor.OfficeAssignment != null)
            {
                currentInstructor.OfficeAssignment.Location
                    = this.officeLocation.Text;
            }
            else
            {
                currentInstructor.OfficeAssignment
                    = OfficeAssignment.CreateOfficeAssignment(
                    currentInstructor.PersonID, this.officeLocation.Text,
                    new byte[8]);
            }
        }
        else
        {
            schoolContext.DeleteObject(currentInstructor
                .OfficeAssignment);
        }
        numChanges = schoolContext.SaveChanges();
        MessageBox.Show(numChanges.ToString() +
            " change(s) saved to the database.");
    }
    catch (OptimisticConcurrencyException oce)
    {
        MessageBox.Show(oce.Message + " The conflict "
            + "occurred on " + oce.StateEntries[0].Entity
            + " with key value " + oce.StateEntries[0].
            EntityKey.EntityKeyValues[0].Value);
    
        //forceChanges.Enabled = true;
    }
    catch (UpdateException ue)
    {
        MessageBox.Show(ue.Message + " Click OK to retrieve "
            + "the latest data from the database.");
        ExecuteInstructorQuery();
        this.Refresh();
    }
    finally
    {
        // Disable the updateOffice button until another
        // change has been made to the location.
        updateOffice.Enabled = false;
    }
    
  10. 返回 OfficeViewer 窗体的设计视图,然后双击 officeLocationTextBox 控件。

    officeLocation_TextChanged 事件处理程序即添加到代码隐藏文件。

  11. 添加一些代码,以便在对所选办公室位置进行更改后启用 updateOfficeButton 控件:

    ' Enable the udateOffice button when there is a change
    ' to write to the database.
    updateOffice.Enabled = True
    
    // Enable the udateOffice button when there is a change
    // to write to the database.
    updateOffice.Enabled = true;
    

现在,就完成了应用程序。按 Ctrl+F5 运行应用程序。现在,即可在 OfficeViewer 窗体中查看和更新办公室信息。

处理并发冲突

在本过程中,将向 Office Viewer 窗体添加代码,以便在发生并发冲突后将客户端更改强制保存到数据库。

处理并发冲突

  1. 在**“解决方案资源管理器”**中双击 InstructorViewer.vbInstructorViewer.cs

    窗体即在窗体设计器中打开。

  2. 双击 View Offices 按钮。

    此时将打开 InstructorViewer 窗体的代码隐藏文件。

  3. 将下面的代码添加到 viewOffices_Click 事件处理程序,以便在单击 View Offices 按钮时加载两个 OfficeViewer 窗体。

    Dim officeViewer2 As New OfficeViewer()
    officeViewer2.Text = "Demonstrate Conflict"
    officeViewer2.Visible = True
    
    OfficeViewer officeViewer2 = new OfficeViewer();
    officeViewer2.Text = "Demonstrate Conflict";
    officeViewer2.Visible = true;
    
  4. 在**“解决方案资源管理器”**中双击 OfficeViewer.vbOfficeViewer.cs

    窗体即在窗体设计器中打开。

  5. Button 控件从工具箱拖到窗体上。将其**“名称”设置为 forceChanges,并将其“文本”**设置为 Force Changes

  6. 双击 Force Changes 按钮。

    此时将打开 Office Viewer 窗体的代码隐藏文件。

  7. 将下面的代码添加到 forceChanges_Click 事件处理程序,以便将客户端上的更改强制保存到服务器,或从数据库刷新绑定到 instructorListComboBox 控件的数据。

    Dim numChanges As Integer
    Dim currentInstructor As Person = CType(Me.instructorList _
        .SelectedItem(), Person)
    Try
        currentInstructor.OfficeAssignment.Location = _
            Me.officeLocation.Text
        ' Using RefreshMode.ClientWins disables the
        ' optimistic concurrency check.
        schoolContext.Refresh(RefreshMode.ClientWins, _
                    currentInstructor.OfficeAssignment)
        numChanges = schoolContext.SaveChanges()
        MessageBox.Show(numChanges.ToString() + _
                " change(s) saved to the database.")
    
        'forceChanges.Enabled = False
    Catch ioe As InvalidOperationException
        MessageBox.Show(ioe.Message + " Click OK to retrieve " _
                + "the latest data from the database.")
        ExecuteInstructorQuery()
        Me.Refresh()
    End Try
    
    int numChanges;
    Person currentInstructor = (Person)this.instructorList
        .SelectedItem;
    try
    {
        currentInstructor.OfficeAssignment.Location
                    = this.officeLocation.Text;
    
        // Using RefreshMode.ClientWins disables the
        // optimistic concurrency check.
        schoolContext.Refresh(RefreshMode.ClientWins,
                currentInstructor.OfficeAssignment);
        numChanges = schoolContext.SaveChanges();
        MessageBox.Show(numChanges.ToString() +
            " change(s) saved to the database.");
    
        //forceChanges.Enabled = false;
    }
    catch (InvalidOperationException ioe)
    {
        MessageBox.Show(ioe.Message + " Click OK to retrieve "
            + "the latest data from the database.");
        ExecuteInstructorQuery();
        this.Refresh();
    }
    
  8. 取消注释 instructorList_SelectedIndexChanged 事件处理程序中的 forceChanges = False (Visual Basic) 或 forceChanges = false; (C#) 代码行,以便在选择新教师时禁用 Force Changes 按钮。

  9. 取消注释 updateOffice_Click 事件处理程序中的 forceChanges = True (Visual Basic) 或 forceChanges = true; (C#) 代码行,以便在发生并发冲突时启用 Force Changes 按钮。

  10. 取消注释 forceChanges_Click 事件处理程序中的 forceChanges = False (Visual Basic) 或 forceChanges = false; (C#) 代码行,以便在将更改强制保存到数据库后禁用 Force Changes 按钮。

若要查看应用程序处理并发冲突,请运行应用程序(按 Ctrl+F5),单击 View Instructors,然后单击 View Offices。在 Office Viewer 窗体中更新一个办公室位置,然后尝试在另一个 Demonstrate Conflict 窗体中更新该办公室位置。此时将出现一个消息框,通知发生了并发冲突。若要将更改从 Demonstrate Conflict 窗体强制保存到数据库,请单击 Force Changes

代码清单

本节包含 InstructorViewerOfficeViewer 窗体的代码隐藏文件的最终版本。

Imports System.Data.Objects
Imports System.Data.Objects.DataClasses
Public Class InstructorViewer

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities

    Private Sub viewOffices_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles viewOffices.Click
        Dim officeViewer As New OfficeViewer()
        officeViewer.Visible = True

        Dim officeViewer2 As New OfficeViewer()
        officeViewer2.Text = "Demonstrate Conflict"
        officeViewer2.Visible = True
    End Sub

    Private Sub InstructorViewer_Load(ByVal sender As System.Object, _
                    ByVal e As System.EventArgs) Handles MyBase.Load
        ' Initialize the ObjectContext.
        schoolContext = New SchoolEntities()
        Dim instructorQuery As ObjectQuery(Of Person) = _
            schoolContext.Person.Include("OfficeAssignment") _
            .Where("it.HireDate is not null") _
            .OrderBy("it.LastName")
        instructorGridView.DataSource = instructorQuery _
            .Execute(MergeOption.OverwriteChanges)
        instructorGridView.Columns("EnrollmentDate").Visible = False
    End Sub

    Private Sub updateInstructor_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles updateInstructor.Click
        Dim numChanges As Integer
        ' Save object changes to the database, display a 
        ' message, and refresh the form.
        numChanges = schoolContext.SaveChanges()
        MessageBox.Show(numChanges.ToString() + _
            " change(s) saved to the database.")
        Me.Refresh()
    End Sub
End Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Objects;
using System.Data.Objects.DataClasses;

namespace CourseManager
{
    public partial class InstructorViewer : Form
    {
        // Create an ObjectContext instance based on SchoolEntity.
        private SchoolEntities schoolContext;

        public InstructorViewer()
        {
            InitializeComponent();
        }

        private void viewOffices_Click(object sender, EventArgs e)
        {
            OfficeViewer officeViewer = new OfficeViewer();
            officeViewer.Visible = true;

            OfficeViewer officeViewer2 = new OfficeViewer();
            officeViewer2.Text = "Demonstrate Conflict";
            officeViewer2.Visible = true;
        }

        private void InstructorViewer_Load(object sender, EventArgs e)
        {
            // Initialize schoolContext.
            schoolContext = new SchoolEntities();

            // Define the query to retrieve instructors.
            ObjectQuery<Person> instructorQuery = schoolContext.Person
                .Include("OfficeAssignment")
                .Where("it.HireDate is not null")
                .OrderBy("it.LastName");

            // Execute and bind the instructorList control to the query.
            instructorGridView.DataSource = instructorQuery.
                Execute(MergeOption.OverwriteChanges);
            instructorGridView.Columns["EnrollmentDate"].Visible = false;
        }

        private void updateInstructor_Click(object sender, EventArgs e)
        {
            int numChanges;
            // Save object changes to the database, display a 
            // message, and refresh the form.
            numChanges = schoolContext.SaveChanges();
            MessageBox.Show(numChanges.ToString() +
                " change(s) saved to the database.");
            this.Refresh();
        }
    }
}
Imports System.Data.Objects
Imports System.Data.Objects.DataClasses
Public Class OfficeViewer

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities

    Private Sub OfficeViewer_Load(ByVal sender As System.Object, _
                ByVal e As System.EventArgs) Handles MyBase.Load
        schoolContext = New SchoolEntities()
        ExecuteInstructorQuery()
    End Sub

    Private Sub instructorList_SelectedIndexChanged(ByVal sender As  _
                System.Object, ByVal e As System.EventArgs) Handles _
                instructorList.SelectedIndexChanged
        Dim instructor As Person = CType(Me.instructorList _
            .SelectedItem(), Person)

        If Not instructor.OfficeAssignment Is Nothing Then
            Me.officeLocation.Text = instructor _
                .OfficeAssignment.Location.ToString()
        Else
            Me.officeLocation.Text = ""
        End If

        ' Disable the updateOffice button until a change
        ' has been made to the office location.
        updateOffice.Enabled = False

        'forceChanges.Enabled = False
    End Sub

    Private Sub updateOffice_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles updateOffice.Click
        Try
            Dim numChanges As Integer
            Dim currentInstructor As Person = CType(Me.instructorList _
                .SelectedItem(), Person)
            If Me.officeLocation.Text <> String.Empty Then
                If Not currentInstructor.OfficeAssignment Is Nothing Then
                    currentInstructor.OfficeAssignment.Location() = _
                        Me.officeLocation.Text
                Else
                    Dim temp(8) As Byte
                    currentInstructor.OfficeAssignment = _
                        OfficeAssignment.CreateOfficeAssignment( _
                        currentInstructor.PersonID, _
                        Me.officeLocation.Text, temp)
                End If
            Else
                schoolContext.DeleteObject(currentInstructor. _
                                           OfficeAssignment)
            End If
            numChanges = schoolContext.SaveChanges()
            MessageBox.Show(numChanges.ToString() _
                    + " change(s) saved to the database.")
        Catch oce As OptimisticConcurrencyException
            MessageBox.Show(oce.Message + " The conflict " & _
                    "occurred on " & oce.StateEntries(0).Entity _
                    .ToString() & "with key value " & _
                    oce.StateEntries(0).EntityKey.EntityKeyValues(0) _
                    .Value)

            'forceChanges.Enabled = True
        Catch ue As UpdateException
            MessageBox.Show(ue.Message & " Click OK to retrieve " _
                    & "the latest data from the database.")
            ExecuteInstructorQuery()
            Me.Refresh()
        Finally
            ' Disable the updateOffice button until another
            ' change has been made to the location.
            updateOffice.Enabled = False
        End Try
    End Sub

    Private Sub officeLocation_TextChanged(ByVal sender As  _
                System.Object, ByVal e As System.EventArgs) _
                Handles officeLocation.TextChanged
        ' Enable the udateOffice button when there is a change
        ' to write to the database.
        updateOffice.Enabled = True
    End Sub

    Private Sub forceChanges_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles forceChanges.Click
        Dim numChanges As Integer
        Dim currentInstructor As Person = CType(Me.instructorList _
            .SelectedItem(), Person)
        Try
            currentInstructor.OfficeAssignment.Location = _
                Me.officeLocation.Text
            ' Using RefreshMode.ClientWins disables the
            ' optimistic concurrency check.
            schoolContext.Refresh(RefreshMode.ClientWins, _
                        currentInstructor.OfficeAssignment)
            numChanges = schoolContext.SaveChanges()
            MessageBox.Show(numChanges.ToString() + _
                    " change(s) saved to the database.")

            'forceChanges.Enabled = False
        Catch ioe As InvalidOperationException
            MessageBox.Show(ioe.Message + " Click OK to retrieve " _
                    + "the latest data from the database.")
            ExecuteInstructorQuery()
            Me.Refresh()
        End Try
    End Sub

    Private Sub ExecuteInstructorQuery()
        ' Define the query to retrieve instructors.
        Dim instructorQuery As ObjectQuery(Of Person) = _
            schoolContext.Person.Include("OfficeAssignment"). _
            Where("it.HireDate is not null").OrderBy("it.LastName")

        'Execute and bind the instructorList control to the query.
        'Using MergeOption.OverwriteChanges overwrites local data
        'with data from the database.
        instructorList.DataSource = instructorQuery _
            .Execute(MergeOption.OverwriteChanges)
        instructorList.DisplayMember = "LastName"
    End Sub
End Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Objects;
using System.Data.Objects.DataClasses;

namespace CourseManager
{
    public partial class OfficeViewer : Form
    {
        // Create an ObjectContext instance based on SchoolEntity.
        private SchoolEntities schoolContext;

        public OfficeViewer()
        {
            InitializeComponent();
        }

        private void OfficeViewer_Load(object sender, EventArgs e)
        {
            schoolContext = new SchoolEntities();
            ExecuteInstructorQuery();
        }

        private void instructorList_SelectedIndexChanged(object sender, 
        EventArgs e)
        {
            Person instructor = (Person)this.instructorList.
                SelectedItem;

            if (instructor.OfficeAssignment != null)
            {
                this.officeLocation.Text = instructor.
                    OfficeAssignment.Location.ToString();
            }
            else
            {
                this.officeLocation.Text = "";
            }

            // Disable the updateOffice button until a change
            // has been made to the office location.
            updateOffice.Enabled = false;

            //forceChanges.Enabled = false;
        }

        private void updateOffice_Click(object sender, EventArgs e)
        {
            try
            {
                int numChanges;
                Person currentInstructor = (Person)this.instructorList.
                    SelectedItem;
                if (this.officeLocation.Text != string.Empty)
                {
                    if (currentInstructor.OfficeAssignment != null)
                    {
                        currentInstructor.OfficeAssignment.Location
                            = this.officeLocation.Text;
                    }
                    else
                    {
                        currentInstructor.OfficeAssignment
                            = OfficeAssignment.CreateOfficeAssignment(
                            currentInstructor.PersonID, this.officeLocation.Text,
                            new byte[8]);
                    }
                }
                else
                {
                    schoolContext.DeleteObject(currentInstructor
                        .OfficeAssignment);
                }
                numChanges = schoolContext.SaveChanges();
                MessageBox.Show(numChanges.ToString() +
                    " change(s) saved to the database.");
            }
            catch (OptimisticConcurrencyException oce)
            {
                MessageBox.Show(oce.Message + " The conflict "
                    + "occurred on " + oce.StateEntries[0].Entity
                    + " with key value " + oce.StateEntries[0].
                    EntityKey.EntityKeyValues[0].Value);

                //forceChanges.Enabled = true;
            }
            catch (UpdateException ue)
            {
                MessageBox.Show(ue.Message + " Click OK to retrieve "
                    + "the latest data from the database.");
                ExecuteInstructorQuery();
                this.Refresh();
            }
            finally
            {
                // Disable the updateOffice button until another
                // change has been made to the location.
                updateOffice.Enabled = false;
            }
        }

        private void officeLocation_TextChanged(object sender, EventArgs e)
        {
            // Enable the udateOffice button when there is a change
            // to write to the database.
            updateOffice.Enabled = true;
        }

        private void forceChanges_Click(object sender, EventArgs e)
        {
            int numChanges;
            Person currentInstructor = (Person)this.instructorList
                .SelectedItem;
            try
            {
                currentInstructor.OfficeAssignment.Location
                            = this.officeLocation.Text;

                // Using RefreshMode.ClientWins disables the
                // optimistic concurrency check.
                schoolContext.Refresh(RefreshMode.ClientWins,
                        currentInstructor.OfficeAssignment);
                numChanges = schoolContext.SaveChanges();
                MessageBox.Show(numChanges.ToString() +
                    " change(s) saved to the database.");

                //forceChanges.Enabled = false;
            }
            catch (InvalidOperationException ioe)
            {
                MessageBox.Show(ioe.Message + " Click OK to retrieve "
                    + "the latest data from the database.");
                ExecuteInstructorQuery();
                this.Refresh();
            }
        }

        private void ExecuteInstructorQuery()
        {
            // Define the query to retrieve instructors.
            ObjectQuery<Person> instructorQuery = schoolContext.Person
                .Include("OfficeAssignment")
                .Where("it.HireDate is not null")
                .OrderBy("it.LastName");

            //Execute and bind the instructorList control to the query.
            //Using MergeOption.OverwriteChanges overwrites local data
            //with data from the database.
            instructorList.DataSource = instructorQuery
                .Execute(MergeOption.OverwriteChanges);
            instructorList.DisplayMember = "LastName";
        }
    }
}

后续步骤

您已成功地将实体的插入、更新和删除操作映射到存储过程。有关实体框架中的存储过程支持的更多信息,请参见存储过程支持(实体框架)。有关如何生成使用实体框架的应用程序的更多信息,请参见编程指南(实体框架)

另请参见

其他资源

ADO.NET 实体数据模型设计器方案
实体数据模型工具任务