演练:将实体映射到存储过程
本主题演示如何使用 ADO.NET 实体数据模型设计器(实体设计器)将实体类型的插入、更新和删除操作映射到存储过程。实体类型的插入、更新和删除操作可以使用系统自动生成的 SQL 语句(默认),也可以使用开发人员所指定的存储过程。无论是否使用存储过程来更新数据库,用于创建、更新和删除实体的应用程序代码都是一样的。
在本演练中,将通过修改 CourseManager 应用程序中所用的实体数据模型 (EDM),将两个实体类型映射到存储过程(有关更多信息,请参见本主题后面的“系统必备”一节)。此外,还将编写用于插入、更新和删除实体类型的代码。
系统必备
要完成本演练,必须生成 CourseManager 应用程序。有关更多信息和说明,请参见实体框架快速入门。生成该应用程序后,将通过把两个实体类型映射到存储过程来修改其 EDM。
注意 |
---|
因为本文档中的许多演练主题都使用该 CourseManager 应用程序作为起点,所以建议在本演练中使用 CourseManager 应用程序的副本,而不要编辑原始 CourseManager 代码。 |
本演练假定读者具备 Visual Studio、.NET Framework 的基本知识,并能使用 Visual C# 或 Visual Basic 进行编程。
将 Person 实体映射到存储过程
将实体的插入操作映射到存储过程时,如果服务器为插入的行创建主键值,则必须将该值映射回实体的键属性。在本示例中,InsertPerson 存储过程返回新创建的主键,作为存储过程的结果集的一部分。主键是使用实体设计器的**“<添加结果绑定>”**功能映射到实体键 (PersonID) 的。
将 Person 实体映射到存储过程
在 Visual Studio 中打开 CourseManager 解决方案。
在解决方案资源管理器中,双击 School.edmx 文件。
该 School.edmx 文件将在 ADO.NET 实体数据模型设计器(实体设计器)中打开。
右键单击 Person 实体类型并选择**“存储过程映射”[Stored Procedure Mapping]**。
存储过程映射将显示在**“映射详细信息”**窗口中。
单击**“<选择插入函数>”**。
该字段即成为一个下拉列表,其中显示 EDM 中包含的存储过程。
从下拉列表中选择 InsertPerson。
此时将显示存储过程参数和实体属性之间的默认映射。请注意,箭头指示映射方向:属性值是提供给存储过程参数的。
单击**“<添加结果绑定>”**。
该字段即变为可编辑状态。
用 InsertPerson 存储过程返回的参数的名称 NewPersonID 替换**“<添加结果绑定>”。按“Enter”**。
默认情况下,NewPersonID 映射到实体键 PersonID。请注意,箭头指示映射方向:结果列的值是提供给属性的。
单击**“<选择更新函数>”**,然后从产生的下拉列表中选择 UpdatePerson。
此时将显示存储过程参数和实体属性之间的默认映射。
单击**“<选择删除函数>”**,然后从产生的下拉列表中选择 DeletePerson。
此时将显示存储过程参数和实体属性之间的默认映射。
现在,Person 实体类型的插入、更新和删除操作即映射到存储过程。
将 OfficeAssignment 实体映射到存储过程
如果将一对一关联某一端的实体类型映射到存储过程,则必须将该关联另一端的实体也映射到存储过程。在本示例中,我们将 OfficeAssignment 实体类型映射到存储过程,因为它和 Person 实体类型具有一对一关联。在此映射中,我们在更新操作中使用**“使用原始值”**选项,以便能够方便地检查应用程序代码中的并发。
将 OfficeAssignment 实体映射到存储过程
右键单击 OfficeAssignment 实体类型并选择 Stored Procedure Mapping。
存储过程映射将显示在**“映射详细信息”**窗口中。
单击**“<选择插入函数>”**,然后从产生的下拉列表中选择 InsertOfficeAssignment。
此时将显示存储过程参数和实体属性之间的默认映射。
单击**“<添加结果绑定>”**。
该字段即变为可编辑状态。
键入 Timestamp 代替**“<添加结果绑定>”**。
单击 Propery/Value 列中 Timestamp 旁的空字段。
该字段即变为一个属性下拉列表,我们可将 InsertOfficeAssignment 存储过程所返回的值映射到其中的属性。
从下拉列表中选择 Timestamp。
单击**“<选择更新函数>”**,然后从产生的下拉列表中选择 UpdateOfficeAssignment。
此时将显示存储过程参数和实体属性之间的默认映射。每个映射的属性旁的**“使用原始值”**列中都会显示复选框。
单击**“属性”**列中对应于 OrigTimestamp 参数的空字段,然后从产生的下拉列表中选择 Timestamp。
因为参数名与属性名不是完全匹配的,所以实体设计器不将它作为默认映射。
选中**“使用原始值”**列中对应于 Timestamp 属性的框。
如果尝试更新,则向数据库写回数据时,将使用最初从数据库读取的 Timestamp 属性的值。如果值与数据库中的值不匹配,将引发 OptimisticConcurrencyException。
单击**“<添加结果绑定>”**。
该字段即变为可编辑状态。
将**“<添加结果绑定>”**替换为 Timestamp。
单击 Propery/Value 列中 Timestamp 旁的空字段。
该字段即变为一个属性下拉列表,我们可将 UpdateOfficeAssignment 存储过程所返回的结果列映射到其中的属性。
从下拉列表中选择 Timestamp。
单击**“<选择删除函数>”**,然后从产生的下拉列表中选择 DeleteOfficeAssignment。
此时将显示存储过程参数和实体属性之间的默认映射。
现在,OfficeAssignment 实体类型的插入、更新和删除操作即映射到存储过程。
构造用户界面
接下来,将两个窗体添加到 CourseManager 应用程序中。一个窗体提供用于查看和更新教师信息的界面。另一个窗体提供用于查看和更新办公室分配的界面。
构造用户界面
在**“解决方案资源管理器”中右键单击 CourseManager 项目,指向“添加”,然后选择“新建项”**。
出现**“添加新项”**对话框。
选择**“Windows 窗体”,将窗体名称设置为“InstructorViewer.vb”或“InstructorViewer.cs”,然后单击“添加”**。
新窗体即被添加到项目中,并在窗体设计器中打开。窗体的名称设置为 InstructorViewer,文本设置为 InstructorViewer。
将 DataGridView 控件从工具箱拖动到窗体上,并在**“属性”窗口中将其“名称”**设置为 instructorGridView。
将 Button 控件从工具箱拖到窗体上。将其**“名称”设置为 updateInstructor,并将其“文本”**设置为 Update Instructor。
将另一个 Button 控件从工具箱拖动到窗体上。将其**“名称”设置为 viewOffices,并将其“文本”**设置为 View Offices。
在**“解决方案资源管理器”中右键单击 CourseManager 项目,指向“添加”,然后选择“新建项”**。
出现**“添加新项”**对话框。
选择**“Windows 窗体”,将窗体名称设置为“OfficeViewer.vb”或“OfficeViewer.cs”,然后单击“添加”**。
新窗体即被添加到项目中,并在窗体设计器中打开。窗体的名称设置为 OfficeViewer,文本设置为 OfficeViewer。
将 ComboBox 控件从工具箱拖动到窗体上,并将其**“名称”**设置为 instructorList。
将 TextBox 控件从工具箱拖动到窗体上,并将其**“名称”**设置为 officeLocation。
将 Button 控件从工具箱拖到窗体上。将其**“名称”设置为 updateOffice,并将其“文本”**设置为 Update Office。
在**“解决方案资源管理器”**中,双击 CourseViewer.vb 或 CourseViewer.cs。
出现 CourseViewer 窗体的设计视图。
将 Button 控件从工具箱拖到窗体上。
在**“属性”窗口中,将 Button 的“名称”属性设置为 viewInstructors,并将“文本”**属性设置为 View Instructors。
双击 viewInstructorsButton 控件。
此时将打开 CourseViewer 窗体的代码隐藏文件。
将下面的代码添加到 viewInstructors_Click 事件处理程序中:
Dim instructorViewer As New InstructorViewer() instructorViewer.Visible = True
InstructorViewer instructorViewer = new InstructorViewer(); instructorViewer.Visible = true;
返回到 InstructorViewer 窗体的设计视图。
双击 viewOfficesButton 控件。
此时将打开 Form2 的代码隐藏文件。
将下面的代码添加到 viewOffices_Click 事件处理程序中:
Dim officeViewer As New OfficeViewer() officeViewer.Visible = True
OfficeViewer officeViewer = new OfficeViewer(); officeViewer.Visible = true;
现在,就完成了用户界面。
查看和更新教师信息
在本过程中,将向 InstructorViewer 窗体添加一些代码,用于查看和更新教师信息。具体而言,这些代码执行以下操作:
将 DataGridView 绑定到用于返回 Person 类型为教师的相关信息的查询。有关将对象绑定到控件的更多信息,请参见将对象绑定到控件(实体框架)。
将 DataGridView 控件中的任何更改(插入、更新或删除)保存到数据库。
在 updateInstructor_Click 事件处理程序中调用 SaveChanges() 时,使用先前映射的存储过程将数据写入数据库。
查看和更新教师信息
在窗体设计器中打开 InstructorViewer 窗体后,双击 InstructorViewer 窗体。
此时将打开 InstructorViewer 窗体的代码隐藏文件。
添加下面的 using (C#) 或 Imports (Visual Basic) 语句:
Imports System.Data.Objects Imports System.Data.Objects.DataClasses
using System.Data.Objects; using System.Data.Objects.DataClasses;
向表示对象上下文的 InstructorViewer 类添加一个属性:
' Create an ObjectContext instance based on SchoolEntity. Private schoolContext As SchoolEntities
// Create an ObjectContext instance based on SchoolEntity. private SchoolEntities schoolContext;
在 InstructorViewer_Load 事件处理程序中,添加代码以初始化对象上下文,并将 DataGridView 控件的数据源设置为用于返回所有不具有 nullHireDate 的 Person 类型的查询。
' 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;
返回 InstructorViewer 窗体的设计视图,然后双击 updateInstructorButton 控件。
updateInstructor_Click 事件处理程序即添加到代码隐藏文件。
将代码添加到 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() 时,使用先前映射的存储过程将数据写入数据库。
查看和更新办公室信息
在窗体设计器中打开 OfficeViewer 窗体后,双击 OfficeViewer 窗体。
此时将打开 OfficeViewer 窗体的代码隐藏文件。
添加下面的 using (C#) 或 Imports (Visual Basic) 语句:
Imports System.Data.Objects Imports System.Data.Objects.DataClasses
using System.Data.Objects; using System.Data.Objects.DataClasses;
向表示对象上下文的 OfficeViewer 类添加一个属性:
' Create an ObjectContext instance based on SchoolEntity. Private schoolContext As SchoolEntities
// Create an ObjectContext instance based on SchoolEntity. private SchoolEntities schoolContext;
将下面的方法添加到窗体:
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 控件。
在 OfficeViewer_Load 事件处理程序中,添加代码以初始化对象上下文,然后调用一个方法将 ComboBox 控件绑定到用于返回所有不具有 nullHireDate 的 Person 类型的查询。
schoolContext = New SchoolEntities() ExecuteInstructorQuery()
schoolContext = new SchoolEntities(); ExecuteInstructorQuery();
返回 OfficeViewer 窗体的设计视图,然后双击 instructorListComboBox 控件。
instructorList_SelectedIndexChanged 事件处理程序即添加到代码隐藏文件。
将代码添加到事件处理程序,用于在 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;
返回 OfficeViewer 窗体的设计视图,然后双击 updateOfficeButton 控件。
updateOffice_Click 事件处理程序即添加到代码隐藏文件。
添加一些代码,用于保存在 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; }
返回 OfficeViewer 窗体的设计视图,然后双击 officeLocationTextBox 控件。
officeLocation_TextChanged 事件处理程序即添加到代码隐藏文件。
添加一些代码,以便在对所选办公室位置进行更改后启用 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 窗体添加代码,以便在发生并发冲突后将客户端更改强制保存到数据库。
处理并发冲突
在**“解决方案资源管理器”**中双击 InstructorViewer.vb 或 InstructorViewer.cs。
窗体即在窗体设计器中打开。
双击 View Offices 按钮。
此时将打开 InstructorViewer 窗体的代码隐藏文件。
将下面的代码添加到 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;
在**“解决方案资源管理器”**中双击 OfficeViewer.vb 或 OfficeViewer.cs。
窗体即在窗体设计器中打开。
将 Button 控件从工具箱拖到窗体上。将其**“名称”设置为 forceChanges,并将其“文本”**设置为 Force Changes。
双击 Force Changes 按钮。
此时将打开 Office Viewer 窗体的代码隐藏文件。
将下面的代码添加到 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(); }
取消注释 instructorList_SelectedIndexChanged 事件处理程序中的
forceChanges = False
(Visual Basic) 或forceChanges = false;
(C#) 代码行,以便在选择新教师时禁用 Force Changes 按钮。取消注释 updateOffice_Click 事件处理程序中的
forceChanges = True
(Visual Basic) 或forceChanges = true;
(C#) 代码行,以便在发生并发冲突时启用 Force Changes 按钮。取消注释 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。
代码清单
本节包含 InstructorViewer 和 OfficeViewer 窗体的代码隐藏文件的最终版本。
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";
}
}
}
后续步骤
您已成功地将实体的插入、更新和删除操作映射到存储过程。有关实体框架中的存储过程支持的更多信息,请参见存储过程支持(实体框架)。有关如何生成使用实体框架的应用程序的更多信息,请参见编程指南(实体框架)。