演练:将一个实体映射到存储过程(实体数据模型工具)

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

在本演练中,您将通过修改在 CourseManager 应用程序中使用的 .edmx 文件将两个实体类型(位于概念模型中)映射到存储过程(位于存储模型中)(有关更多信息,请参见本主题后面的“先决条件”一节)。 此外,还将编写用于插入、更新和删除实体类型的代码。

Cc716679.note(zh-cn,VS.100).gif注意:
如果没有将实体类型的插入、更新或删除这三种操作全部映射到存储过程,则在运行时执行的情况下未映射的操作将失败且会引发 UpdateException

必备条件

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

Cc716679.note(zh-cn,VS.100).gif注意:
因为本文档中的许多演练主题都使用该 CourseManager 应用程序作为起点,所以建议在本演练中使用 CourseManager 应用程序的副本,而不要编辑原始 CourseManager 代码。

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

将 Person 实体映射到存储过程

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

Cc716679.note(zh-cn,VS.100).gif注意:
如果将插入、更新或删除操作映射到返回整数值输出参数的存储过程,则启用“受影响的行数参数”复选框。如果在调用操作时针对某参数选中该复选框且返回的值为零,将引发 OptimisticConcurrencyException

将 Person 实体映射到存储过程

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

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

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

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

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

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

    该字段变成一个下拉列表,该列表中包含存储模型中可以映射到概念模型中的实体类型的存储过程。

  5. 从下拉列表中选择 InsertPerson

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

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

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

  7. 键入 NewPersonID,它是由 InsertPerson 存储过程返回的参数的名称。 按**“Enter”**。

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

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

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

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

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

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

将 OfficeAssignment 实体映射到存储过程

在本示例中,我们将 OfficeAssignment 实体类型映射到存储过程。 在此映射中,我们在更新操作中使用**“使用原始值”**选项,以便能够方便地检查应用程序代码中的并发。

将 OfficeAssignment 实体映射到存储过程

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

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

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

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

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

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

  4. 键入 Timestamp

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

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

  6. 从下拉列表中选择 Timestamp

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

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

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

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

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

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

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

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

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

  12. 单击 Property/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. 双击 viewInstructors Button 控件。

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

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

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

  17. 双击 viewOffices Button 控件。

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

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

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

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

查看和更新教师信息

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

  • DataGridView 绑定到用于返回 Person 类型为教师的相关信息的查询。 有关将对象绑定到控件的更多信息,请参见Binding Objects to Controls (Entity Framework)

  • 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 控件的数据源设置为用于返回所有不具有 null HireDatePerson 类型的查询。

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

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

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

    ' Save object changes to the database, display a 
    ' message, and refresh the form.
    schoolContext.SaveChanges()
    MessageBox.Show("Change(s) saved to the database.")
    Me.Refresh()
    
    // Save object changes to the database, display a 
    // message, and refresh the form.
    schoolContext.SaveChanges();
    MessageBox.Show("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.People.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.People
            .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";
    }
    

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

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

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

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

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

    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 窗体的设计视图,然后双击 updateOffice Button 控件。

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

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

    Try
        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
        schoolContext.SaveChanges()
        MessageBox.Show("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
    {
        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);
        }
        schoolContext.SaveChanges();
        MessageBox.Show("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 窗体的设计视图,然后双击 officeLocation TextBox 控件。

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

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

    ' 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 事件处理程序,以便将客户端上的更改强制保存到服务器,或从数据库刷新绑定到 instructorList ComboBox 控件的数据。

    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)
        schoolContext.SaveChanges()
        MessageBox.Show("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
    
    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);
        schoolContext.SaveChanges();
        MessageBox.Show("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.People.Include("OfficeAssignment") _
            .Where("it.HireDate is not null") _
            .OrderBy("it.LastName")
        instructorGridView.DataSource = instructorQuery _
            .Execute(MergeOption.OverwriteChanges)
        instructorGridView.Columns("EnrollmentDate").Visible = False
        instructorGridView.Columns("EnrollmentDate").Visible = False
        instructorGridView.Columns("OfficeAssignment").Visible = False
        instructorGridView.Columns("StudentGrades").Visible = False
        instructorGridView.Columns("Courses").Visible = False
    End Sub

    Private Sub updateInstructor_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles updateInstructor.Click
        ' Save object changes to the database, display a 
        ' message, and refresh the form.
        schoolContext.SaveChanges()
        MessageBox.Show("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.People
                .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;
            instructorGridView.Columns["OfficeAssignment"].Visible = false;
            instructorGridView.Columns["StudentGrades"].Visible = false;
            instructorGridView.Columns["Courses"].Visible = false;
        }

        private void updateInstructor_Click(object sender, EventArgs e)
        {
            // Save object changes to the database, display a 
            // message, and refresh the form.
            schoolContext.SaveChanges();
            MessageBox.Show("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 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
            schoolContext.SaveChanges()
            MessageBox.Show("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 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)
            schoolContext.SaveChanges()
            MessageBox.Show("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.People.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
            {
                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);
                }
                schoolContext.SaveChanges();
                MessageBox.Show("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)
        {
            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);
                schoolContext.SaveChanges();
                MessageBox.Show("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.People
                .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";
        }
    }
}

后续步骤

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

另请参见

其他资源

实体数据模型工具方案
实体数据模型工具任务