Пошаговое руководство: сопоставление сущности с хранимыми процедурами
В этом разделе показано, как использовать конструктор моделей EDM ADO.NET (конструктор сущностей) для сопоставления операций вставки, обновления и удаления типа сущности с хранимыми процедурами. В операциях вставки, обновления и удаления типа сущности могут использоваться инструкции SQL, автоматически формируемые системой (по умолчанию), или хранимые процедуры, которые определены разработчиком. Код приложения, используемый для создания, обновления и удаления сущностей, остается неизменным независимо от того, используются ли для обновления базы данных хранимые процедуры.
В этом пошаговом руководстве показано, как сопоставить два типа сущности с хранимыми процедурами путем изменения модели EDM, используемой в приложении CourseManager (дополнительные сведения см. в подразделе «Предварительные условия» ниже в этом разделе). Кроме того, показано, как написать код, с помощью которого осуществляется вставка, обновление и удаление типов сущности.
Предварительные требования
Для работы с этим пошаговым руководством необходимо построить приложение CourseManager. Дополнительные сведения и команды см. в разделе Краткое руководство по Entity Framework. После построения этого приложения необходимо изменить его модель EDM путем сопоставления двух типов сущности с хранимыми процедурами.
Примечание. |
---|
Приложение CourseManager используется в качестве отправной точки во многих разделах пошагового руководства в данной документации, поэтому рекомендуется использовать для данного пошагового руководства копию приложения CourseManager, а не вносить изменения в первоначальный код CourseManager. |
В этом пошаговом руководстве предполагается, что читатель обладает основными навыками работы со средой Visual Studio и платформой .NET Framework, а также навыками программирования на языке Visual C# или Visual Basic.
Сопоставление сущности Person с хранимыми процедурами
При сопоставлении операции вставки сущности с хранимой процедурой необходимо учитывать, что, если сервер создает значение первичного ключа для вставленной строки, это значение должно быть снова сопоставлено со свойством ключа сущности. В этом примере хранимая процедура InsertPerson возвращает вновь созданный первичный ключ как часть результирующего набора хранимой процедуры. Первичный ключ сопоставляется с ключом сущности (PersonID) при помощи средства <Добавление привязок результатов> конструктора сущностей.
Сопоставление сущности Person с хранимыми процедурами
Откройте решение CourseManager в среде Visual Studio.
В обозревателе решений дважды щелкните файл School.edmx.
Файл School.edmx открывается в конструкторе моделей EDM ADO.NET (в конструкторе сущностей).
Щелкните правой кнопкой мыши тип сущности Person и выберите пункт Сопоставление хранимых процедур.
Сопоставления хранимых процедур появятся в окне Сведения о сопоставлении.
Щелкните элемент <Выбор функции вставки>.
Это поле преобразуется в раскрывающийся список хранимых процедур, включенных в модель EDM.
Выберите InsertPerson из раскрывающегося списка.
Появятся применяемые по умолчанию сопоставления параметров хранимой процедуры со свойствами сущности. Обратите внимание на то, что направление сопоставления указывают стрелки: значения свойств передаются параметрам хранимой процедуры.
Щелкните элемент <Добавление привязки к результату>.
Поле становится изменяемым.
Замените значение <Добавление привязки к результату> значением NewPersonID, именем параметра, возвращенного хранимой процедурой InsertPerson. Нажмите клавишу ВВОД.
По умолчанию значение 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 Form, задайте в качестве значения формы InstructorViewer.vb или InstructorViewer.cs и щелкните элемент Добавить.
Новая форма будет добавлена к проекту и открыта в конструкторе форм. Для формы устанавливается имя InstructorViewer и текст InstructorViewer.
Перетащите элемент управления DataGridView из области элементов в форму и задайте для свойства Имя значение instructorGridView в окне Свойства.
Перетащите элемент управления Button из области элементов в форму. Задайте для его свойства Имя значение updateInstructor, а для свойства Текст значение Update Instructor.
Перетащите еще один элемент управления Button из области элементов в форму. Задайте для его свойства Имя значение viewOffices, а для свойства Текст значение View Offices.
Щелкните правой кнопкой мыши имя проекта CourseManager в окне Обозреватель решений, укажите пункт Добавить и выберите пункт Новый элемент.
Появится диалоговое окно Добавление нового элемента.
Выберите элемент Windows Form, задайте для имени формы значение 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, представляющих преподавателей. Дополнительные сведения о привязке объектов к элементам управления см. в разделе Привязка объектов к элементам управления (платформа Entity Framework).
Сохранение любых изменений (вставки, обновления или удаления) элемента управления DataGridView в базе данных.
Использование сопоставленных ранее хранимых процедур для записи данных в базу данных при вызове метода SaveChanges() в обработчике события updateInstructor_Click.
Просмотр и обновление сведений о преподавателях
При открытой форме 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 запрос, который возвращает все типы Person, не имеющие свойств nullHireDate.
' 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.
Использование сопоставленных ранее хранимых процедур для записи данных в базу данных при вызове метода SaveChanges() в обработчике события updateOffice_Click.
Просмотр и обновление сведений об аудитории
При открытой форме 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 к запросу, возвращающему все типы Person, не имеющие свойства nullHireDate.
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, чтобы загружались две формы OfficeViewer при нажатии кнопки View Offices.
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(); }
Уберите комментарий из строки кода
forceChanges = False
(Visual Basic) илиforceChanges = false;
(C#) в обработчике события instructorList_SelectedIndexChanged, чтобы кнопка Force Changes была отключена при выборе нового преподавателя.Уберите комментарий из строки кода
forceChanges = True
(Visual Basic) илиforceChanges = true;
(C#) в обработчике события updateOffice_Click, чтобы кнопка Force Changes была включена при возникновении конфликта параллелизма.Уберите комментарий из строки кода
forceChanges = False
(Visual Basic) илиforceChanges = false;
(C#) в обработчике события forceChanges_Click, чтобы кнопка 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";
}
}
}
Следующие шаги
Предпринятая попытка сопоставления операций вставки, обновления и удаления сущности с хранимыми процедурами окончилась успешно. Дополнительные сведения о поддержке хранимых процедур в Entity Framework см. в разделе Поддержка хранимых процедур (платформа Entity Framework). Дополнительные сведения о построении приложений, использующих платформу Entity Framework, см. в разделе Руководство по программированию (платформа Entity Framework).
См. также
Другие ресурсы
Сценарии конструктора моделей EDM ADO.NET
Задачи средств модели EDM