逐步解說:將實體對應至預存程序
本主題示範如何使用 ADO.NET 實體資料模型設計工具 (Entity Designer) 將實體類型的插入、更新和刪除作業對應至預存程序 (Stored Procedure)。實體類型的插入、更新和刪除作業可以使用系統 (預設值) 所自動產生的 SQL 陳述式 (Statement),或者可以使用開發人員所指定的預存程序。不論是否有使用預存程序來更新資料庫,建立、更新和刪除實體所用的應用程式程式碼都相同。
在本逐步解說中,您將修改 CourseManager 應用程式內使用的 Entity Data Model (EDM),藉以將兩個實體類型對應至預存程序 (如需詳細資訊,請參閱本主題稍後的<必要條件>章節)。您也將撰寫會插入、更新和刪除實體類型的程式碼。
必要條件
若要完成本逐步解說,必須建置 CourseManager 應用程式。如需詳細資訊和指示,請參閱 Entity Framework 快速入門。在建置此應用程式之後,您必須將兩個實體類型對應至預存程序,藉以修改其 EDM。
注意: |
---|
因為本說明文件的許多逐步解說主題都從使用 CourseManager 應用程式開始,建議您為本逐步解說使用 CourseManager 應用程式的複本,而非編輯原始的 CourseManager 程式碼。 |
本逐步解說假設讀者具備以下基本能力:Visual Studio 和 .NET Framework 的使用能力,以及 Visual C# 或 Visual Basic 程式設計的能力。
將 Person 實體對應至預存程序
當您將實體的插入作業對應至預存程序時,如果伺服器為插入的資料列建立主索引鍵值,您就必須將這個值對應回實體的索引鍵屬性。在這個範例中,InsertPerson 預存程序會傳回新建立的主索引鍵做為預存程序之結果集 (Result Set) 的一部分。Entity Designer 的 [<加入結果繫結>] 功能是用來將主索引鍵對應至實體索引鍵 (PersonID)。
若要將 Person 實體對應至預存程序
在 Visual Studio 中開啟 CourseManager 方案。
按兩下 [方案總管] 中的 School.edmx 檔案。
School.edmx 檔案隨即在 ADO.NET 實體資料模型設計工具 (Entity Designer) 中開啟。
以滑鼠右鍵按一下 [Person] 實體類型,然後選取 [預存程序對應]。
預存程序對應隨即在 [對應詳細資料] 視窗中出現。
按一下 [<選取插入函式>]。
欄位會變成 EDM 中所含之預存程序的下拉式清單。
從下拉式清單中選取 InsertPerson。
預存程序參數與實體屬性之間的預設對應隨即出現。請注意,箭頭表示對應方向:為預存程序參數提供屬性值。
按一下 [<加入結果繫結>]。
欄位會變成可編輯的狀態。
以 NewPersonID (由 InsertPerson 預存程序傳回的參數名稱) 來取代 [<加入結果繫結>],然後按 Enter。
根據預設,NewPersonID 會對應至 PersonID 實體索引鍵。請注意,箭頭表示對應方向:為屬性提供結果資料行的值。
按一下 [<選取更新函式>],然後從產生的下拉式清單中選取 UpdatePerson。
預存程序參數與實體屬性之間的預設對應隨即出現。
按一下 [<選取刪除函式>],然後從產生的下拉式清單中選取 DeletePerson。
預存程序參數與實體屬性之間的預設對應隨即出現。
Person 實體類型的插入、更新和刪除作業現在都已對應至預存程序了。
將 OfficeAssignment 實體對應至預存程序
如果位於一對一關聯一端的實體類型對應至預存程序,則位於關聯另一端的實體也必須對應至預存程序。在這個範例中,會將 OfficeAssignment 實體類型對應至預存程序,因為它與 Person 實體類型有一對一關聯。在這項對應中,則會在更新作業上使用 [使用原始值 ] 選項,以便於能夠對應用程式程式碼檢查並行存取。
若要將 OfficeAssignment 實體對應至預存程序
以滑鼠右鍵按一下 [OfficeAssignment] 實體類型,然後選取 [Stored Procedure Mapping]。
預存程序對應隨即在 [對應詳細資料] 視窗中出現。
按一下 [<選取插入函式>],然後從產生的下拉式清單中選取 InsertOfficeAssignment。
預存程序參數與實體屬性之間的預設對應隨即出現。
按一下 [<加入結果繫結>]。
欄位會變成可編輯的狀態。
輸入 Timestamp,以取代 [<加入結果繫結>]。
在 Timestamp 旁邊的 [Propery/Value] 資料行中按一下空白欄位。
欄位會變成我們可以對應由 InsertOfficeAssignment 預存程序傳回的值之屬性的下拉式清單。
從下拉式清單中選取 Timestamp。
按一下 [<選取更新函式>],然後從產生的下拉式清單中選取 UpdateOfficeAssignment。
預存程序參數與實體屬性之間的預設對應隨即出現。核取方塊會在每個對應屬性旁邊的 [使用原始值] 資料行中顯示。
在對應至 OrigTimestamp 參數的 [屬性] 資料行中按一下空白欄位,然後從產生的下拉式清單中選取 Timestamp。
Entity Designer 沒有產生這項預設對應,因為參數名稱沒有完全符合屬性名稱。
在對應至 Timestamp 屬性的 [使用原始值] 資料行中選取方塊。
當嘗試更新的時候,會在將資料寫回資料庫時使用原本從資料庫讀取的 Timestamp 屬性值。如果這個值與資料庫中的值不相符,則會擲回 OptimisticConcurrencyException。
按一下 [<加入結果繫結>]。
欄位會變成可編輯的狀態。
以 Timestamp 來取代 [<加入結果繫結>]。
在 Timestamp 旁邊的 [Propery/Value] 資料行中按一下空白欄位。
欄位會變成我們可以對應由 UpdateOfficeAssignment 預存程序傳回的結果資料行之屬性的下拉式清單。
從下拉式清單中選取 Timestamp。
按一下 [<選取刪除函式>],然後從產生的下拉式清單中選取 DeleteOfficeAssignment。
預存程序參數與實體屬性之間的預設對應隨即出現。
OfficeAssignment 實體類型的插入、更新和刪除作業現在都已對應至預存程序了。
建構使用者介面
接下來,您將加入兩個表單至 CourseManager 應用程式。一個表單提供檢視和更新講師資訊用的介面,另一個表單則提供檢視和更新辦公室分配用的介面。
若要建構使用者介面
以滑鼠右鍵按一下 [方案總管] 中的 CourseManager 專案,然後指向 [加入],再選取 [新增項目]。
[加入新項目] 對話方塊隨即出現。
選取 [Windows Form],然後將表單的名稱設為 InstructorViewer.vb 或 InstructorViewer.cs,再按一下 [加入]。
新的表單隨即加入至專案並在表單設計工具中開啟。這個表單的名稱已設為 InstructorViewer,而且文字已設為 InstructorViewer。
將 DataGridView 控制項從 [工具箱] 拖曳至表單,並在 [屬性] 視窗中將它的 [Name] 設為 instructorGridView。
將 Button 控制項從 [工具箱] 拖曳至表單。將它的 [Name] 設為 updateInstructor,以及它的 [Text] 設為 Update Instructor。
將另一個 Button 控制項從 [工具箱] 拖曳至表單。將它的 [Name] 設為 viewOffices,以及它的 [Text] 設為 View Offices。
以滑鼠右鍵按一下 [方案總管] 中的 CourseManager 專案,然後指向 [加入],再選取 [新增項目]。
[加入新項目] 對話方塊隨即出現。
選取 [Windows Form],然後將表單的名稱設為 OfficeViewer.vb 或 OfficeViewer.cs,再按一下 [加入]。
新的表單隨即加入至專案並在表單設計工具中開啟。這個表單的名稱已設為 OfficeViewer,而且文字已設為 OfficeViewer。
將 ComboBox 控制項從 [工具箱] 拖曳至表單,並將它的 [Name] 設為 instructorList。
將 TextBox 控制項從 [工具箱] 拖曳至表單,並將它的 [Name] 設為 officeLocation。
將 Button 控制項從 [工具箱] 拖曳至表單。將它的 [Name] 設為 updateOffice,以及它的 [Text] 設為 Update Office。
按兩下 [方案總管] 中的 CourseViewer.vb 或 CourseViewer.cs。
CourseViewer 表單的設計檢視隨即出現。
將 Button 控制項從 [工具箱] 拖曳至表單。
在 [屬性] 視窗中將 Button 的 [Name] 屬性設為 viewInstructors,以及將 [Text] 屬性設為 View Instructors。
按兩下 viewInstructorsButton 控制項。
CourseViewer 表單之程式碼後置(Code-Behind) 的檔案隨即開啟。
將下列程式碼加入至 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 型別是講師之相關資訊的查詢。如需將物件繫結至控制項的詳細資訊,請參閱Binding Objects to Controls (Entity Framework)。
將 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.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;
回到 InstructorViewer 表單的設計檢視,然後按兩下 updateInstructorButton 控制項。
updateInstructor_Click 事件處理常式會加入至程式碼後置的檔案。
將程式碼加入至 updateInstructor_Click 事件處理常式,它會儲存對 instructorGridViewDataGridView 控制項中的講師資訊所做的任何變更。
' 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() 時,使用先前所對應的預存程序將資料寫入資料庫。
若要檢視和更新辦公室資訊
表單設計工具中已開啟 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.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"; }
這個方法會執行一個可傳回講師資訊並將結果繫結至 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 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; }
回到 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 控制項從 [工具箱] 拖曳至表單。將它的 [Name] 設為 forceChanges,以及它的 [Text] 設為 Force Changes。
按兩下 [Force Changes] 按鈕。
Office Viewer 表單之程式碼後置的檔案隨即開啟。
將下列程式碼加入至 forceChanges_Click 事件處理常式,以便對伺服器強制進行用戶端變更,或從資料庫重新整理繫結至 instructorListComboBox 控制項的資料。
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(); }
在 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.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 中預存程序之支援的詳細資訊,請參閱Stored Procedure Support (Entity Framework)。如需如何建置使用 Entity Framework 之應用程式的詳細資訊,請參閱Programming Guide (Entity Framework)。