Пошаговое руководство по выполнению сериализации сущностей с самостоятельным отслеживанием (платформа Entity Framework)
Пошаговое руководство в данном разделе использует сценарий, в котором служба Windows Communication Foundation (WCF) предоставляет доступ к серии операций, возвращающих графы сущностей. Затем клиентское приложение обрабатывает этот граф и передает изменения операции службы, которая проверяет изменения и сохраняет их в базу данных с помощью платформы Entity Framework. Дополнительные сведения см. в разделе Работа с сущностями с самостоятельным отслеживанием.
Рекомендуется отделять проект модели от проекта, содержащего типы сущности с самостоятельным отслеживанием. В этом случае в конкретный клиент нужно будет включить только проект с типами сущности.
Один из способов обеспечить эту изоляцию состоит в том, чтобы отделить типы сущности с самостоятельным отслеживанием от модели и переместить шаблон, формирующий типы сущности, в отдельную библиотеку классов. Для доступа к метаданным в шаблон сущностей с самостоятельным отслеживанием следует включить местоположение EDMX-файла. При перемещении шаблона из первоначального проекта в другой необходимо открыть файл шаблона в редакторе и изменить строку inputFile, указав относительный путь к EDMX-файлу. Дополнительные сведения о работе с шаблонами см. в разделе ADO.NET Self-Tracking Entity Template.
Еще один способ разделения типов сущности и модели — это оставить файл шаблона в исходном проекте и отключить создание кода для шаблона. Ссылка указывает на шаблон из другого проекта, поэтому код сформируется в этом другом проекте вместо исходного. При добавлении элемента в проект в виде ссылки актуальный контекст элемента поддерживается в месте, указанном в исходном проекте. Этот метод разделения типов сущности и модели показан в этом пошаговом руководстве.
В этом пошаговом руководстве выполняются следующие действия.
Создается проект библиотеки классов, содержащий модель, построенную на основе School.
Шаблон генератора сущностей ADO.NET с самостоятельным отслеживанием используется для формирования типов сущности, типизированного контекста ObjectContext и класса расширения, содержащего перегруженные методы ApplyChanges.
Создается проект библиотеки классов, связанный с шаблоном типов сущности с самостоятельным отслеживанием, созданным в первом проекте.
Создается служба WCF, которая обеспечивает доступ к набору операций, возвращающих графы сущностей, и с помощью Entity Framework применяет изменения, сделанные на клиенте, к базе данных.
Создает клиентские приложения (консольное и WPF), которые обрабатывают граф и фиксируют изменения с помощью операций, доступ к которым предоставляет служба WCF.
Примечание |
---|
Пример STESchoolModelExample можно загрузить на сайте Entity Framework Documentation Samples MSDN Code Gallery. |
Создание проекта библиотеки классов, содержащего сущности с самостоятельным отслеживанием и классы контекста объекта
Создайте новый проект библиотеки классов. Введите STESchoolModel в качестве имени проекта и решения.
Удалите файл исходного кода по умолчанию, добавленный к проекту.
С помощью мастера моделей EDM создайте модель на основе таблиц Department, Course, OnlineCourse и OnsiteCourse в базе данных School. Дополнительные сведения см. в разделе School, модель.
Откройте EDMX-файл в конструкторе сущностей (ADO.NET Entity Data Model Designer).
Следуйте инструкциям по сопоставлению наследования из раздела Walkthrough: Mapping Inheritance - Table-per-Type.
Щелкните правой кнопкой мыши пустой участок области конструктора сущностей, выберите Добавить элемент формирования кода, а затем Генератор сущностей с самостоятельным отслеживанием ADO.NET. Измените имя по умолчанию для шаблона на SchoolModel.
Примечание После добавления файлов шаблонов в проект может появиться предупреждение безопасности, запрашивающее подтверждение надежности источника шаблона.Нажмите кнопку Принять. Папки SchoolModel.Context.tt и SchoolModel.tt добавляются в проект. В папке SchoolModel.Context.tt содержатся два файла, определяющие типизированный контекст ObjectContext и класс расширения, содержащий перегруженные методы ApplyChanges. В папке SchoolModel.tt находятся файлы, определяющие типы сущности, и вспомогательный класс, содержащий логику отслеживания изменений, используемую сущностями с самостоятельным отслеживанием.
Следующие два шага иллюстрируют отключение создания кода в данном проекте. Создание кода будет включено позже для типов STESchoolModelTypes в библиотеке классов и для контекста объекта в STESchoolModelService.
Выберите SchoolModel.tt. В окне Свойства удалите TextTemplatingFileGenerator из свойства CustomTool. Удалите файлы в папке SchoolModel.tt.
Выберите SchoolModel.Context.tt. В окне Свойства очистите значение свойства CustomTool. Удалите файлы в папке SchoolModel.Context.tt.
При работе с проектом Visual Basic, чтобы увидеть все файлы проекта, может потребоваться выбрать Показать все файлы в обозревателе решений.
Скомпилируйте проект.
Создание проекта библиотеки классов, ссылающегося на шаблон типов с самостоятельным отслеживанием
Создайте новый проект библиотеки классов с именем STESchoolModelTypes в том же решении, что и предыдущий проект.
Удалите файл исходного кода по умолчанию, добавленный к проекту.
Добавьте ссылку на файл SchoolModel.tt, чтобы типы сущности с самостоятельным отслеживанием формировались в этом решении. В окне Обозреватель решений щелкните правой кнопкой мыши STESchoolModelTypes, выберите Добавить, затем Существующий элемент.
В диалоговом окне Добавление существующего элемента найдите проект STESchoolModel и щелкните SchoolModel.tt (не нажимайте клавишу ВВОД). В списке Добавить выберите команду Добавить как связь.
Добавьте ссылку на библиотеку System.Runtime.Serialization. Эта библиотека нужна для DataContract WCF и для атрибутов DataMember, используемых для сериализуемых типов сущности.
Скомпилируйте проект.
Создание и конфигурирование проекта приложения службы WCF
Создайте проект приложения службы WCF с именем STESchoolModelService в том же решении, что и предыдущий проект.
Добавьте ссылку на System.Data.Entity.dll.
Добавьте ссылку на проекты STESchoolModel и STESchoolModelTypes.
Добавьте ссылку на файл SchoolModel.Context.tt, чтобы типы контекста формировались в этом решении. В окне Обозреватель решений щелкните правой кнопкой мыши STESchoolModelService, выберите Добавить, затем Существующий элемент.
В диалоговом окне Добавление существующего элемента загрузите проект STESchoolModel и щелкните SchoolModel.Context.tt (не нажимайте клавишу ВВОД). В списке Добавить выберите команду Добавить как связь.
В окне «Свойства» файла SchoolModel.Context.tt введите значение STESchoolModelService для свойства Пространство имен CustomTool. Тип контекста объекта будет добавлен в то же самое пространство имен, где находятся типы сущности с самостоятельным отслеживанием. Это обязательно.
(Только для Visual Basic) Добавьте
Import STESchoolModelTypes
к файлам исходного кода, созданным на основе файла SchoolModel.Context.tt. Откройте файл SchoolModel.Context.tt и найдите строкуImports System
. После других команд импорта добавьтеImport STESchoolModelTypes
. Сформированные файлы исходного кода будут включать в себя это пространство имен.Добавьте строку подключения в файл Web.config, чтобы среда выполнения Entity Framework могла найти метаданные. Откройте файл app.config проекта STESchoolModel . Скопируйте элемент connectionStrings, а затем добавьте его как дочерний элемент configuration в файл Web.config.
Откройте файл интерфейса службы. По умолчанию он называется IService1.
Добавьте пространство имен, где определены сущности с самостоятельным отслеживанием: STESchoolModelTypes.
Замените определение интерфейса служб следующим кодом:
<ServiceContract()> _ Public Interface IService1 <OperationContract()> _ Sub UpdateDepartment(ByVal updated As Department) <OperationContract()> _ Function GetDepartments() As List(Of Department) End Interface
[ServiceContract] public interface IService1 { [OperationContract] void UpdateDepartment(Department updated); [OperationContract] List<Department> GetDepartments(); }
Откройте исходный код службы. По умолчанию он называется Service1.srv.cs (или Service1.srv.vb).
Добавьте пространство имен, где определены сущности с самостоятельным отслеживанием: STESchoolModelTypes.
(Только для Visual Basic) Добавьте
Imports STESchoolModelService.STESchoolModelTypes
в файл Service1.srv.cs.Замените определение класса служб следующим кодом:
Примечание |
---|
Перед тем как применить изменения, всегда следует проводить проверку измененного объекта. |
Public Class Service1
Implements IService1
''' <summary>
''' Updates department and its related courses.
''' </summary>
Public Sub UpdateDepartment(ByVal updated As Department) Implements IService1.UpdateDepartment
Using context As New STESchoolModelTypes.SchoolEntities()
Try
' Perform validation on the updated order before applying the changes.
' The ApplyChanges method examines the change tracking information
' contained in the graph of self-tracking entities to infer the set of operations
' that need to be performed to reflect the changes in the database.
context.Departments.ApplyChanges(updated)
context.SaveChanges()
Catch ex As UpdateException
' To avoid propagating exception messages that contain sensitive data to the client tier,
' calls to ApplyChanges and SaveChanges should be wrapped in exception handling code.
Throw New InvalidOperationException("Failed to update the department. Try your request again.")
End Try
End Using
End Sub
''' <summary>
''' Gets all the departments and related courses.
''' </summary>
Public Function GetDepartments() As List(Of Department) Implements IService1.GetDepartments
Using context As New STESchoolModelTypes.SchoolEntities()
' Use System.Data.Objects.ObjectQuery(T).Include to eagrly load the related courses.
Return context.Departments.Include("Courses").OrderBy(Function(d) d.Name).ToList()
End Using
End Function
End Class
public class Service1 : IService1
{
/// <summary>
/// Updates department and its related courses.
/// </summary>
public void UpdateDepartment(Department updated)
{
using (SchoolEntities context =
new SchoolEntities())
{
try
{
// Perform validation on the updated order before applying the changes.
// The ApplyChanges method examines the change tracking information
// contained in the graph of self-tracking entities to infer the set of operations
// that need to be performed to reflect the changes in the database.
context.Departments.ApplyChanges(updated);
context.SaveChanges();
}
catch (UpdateException ex)
{
// To avoid propagating exception messages that contain sensitive data to the client tier,
// calls to ApplyChanges and SaveChanges should be wrapped in exception handling code.
throw new InvalidOperationException("Failed to update the department. Try your request again.");
}
}
}
/// <summary>
/// Gets all the departments and related courses.
/// </summary>
public List<Department> GetDepartments()
{
using (SchoolEntities context = new SchoolEntities())
{
// Use System.Data.Objects.ObjectQuery(T).Include to eagrly load the related courses.
return context.Departments.Include("Courses").OrderBy(d => d.Name).ToList();
}
}
}
Проверка службы с помощью консольного клиентского приложения
Создайте консольное приложение. Введите STESchoolModelTest в качестве имени проекта в том же решении, что и в предыдущем проекте.
Добавьте ссылку на службу STEASchoolModelService. Для добавления ссылки на службу щелкните правой кнопкой мыши папку ссылок в обозревателе решений и выберите Добавить ссылку на службу.
По умолчанию WCF создает прокси-объект, возвращающий коллекцию IEnumerable. Поскольку в службе STESchoolModelService метод GetDepartments возвращает List, следует сконфигурировать службу так, чтобы задать соответствующий тип возврата.
Щелкните правой кнопкой мыши имя службы (ServiceReference1) и выберите Настроить ссылку на службу…. В диалоговом окне «Настроить ссылку на службу» выберите тип System.Collections.Generic.List из списка Тип коллекции.
Добавьте ссылку на проект STESchoolModelTypes .
Откройте файл app.config и добавьте в файл строку подключения. Откройте файл app.config проекта STESchoolModel и скопируйте элемент connectionStrings, чтобы добавить его в качестве дочернего элемента configuration в файле Web.config.
Откройте файл, содержащий функцию main. Включите следующие пространства имен: STESchoolModelTest.ServiceReference1 и STESchoolModelTypes (где определены типы с самостоятельным отслеживанием).
Вставьте следующий код в функцию main вашего проекта. Этот код содержит вызовы методов, которые мы определим на следующем шаге.
' Note, the service's GetDepartments method returns System.Collections.Generic.List. ' By default, when WCF generates a proxy the return collection types are converted to IEnumerable. ' The WCF service has to be configured to specify the List return type. ' To specify the List collection type, open the Configure Service Reference dialog and ' select the System.Collections.Generic.List type from the Collection type list. Console.WriteLine("See the existing departments and courses.") DisplayDepartmentsAndCourses() Console.WriteLine() Console.WriteLine() ' Use some IDs to create ' new Department and Course. ' The newly created objects will ' be then deleted. Dim departmentID As Integer = 100 Dim courseID As Integer = 50 AddNewDepartmentAndCourses(departmentID, courseID) Console.WriteLine("See existing and added.") DisplayDepartmentsAndCourses() Console.WriteLine() UpdateDepartmentAndCourses(departmentID, courseID) Console.WriteLine("See existing and updated.") DisplayDepartmentsAndCourses() Console.WriteLine() DeleteDepartmentAndCourses(departmentID)
// Note, the service's GetDepartments method returns System.Collections.Generic.List. // By default, when WCF generates a proxy the return collection types are converted to IEnumerable. // The WCF service has to be configured to specify the List return type. // To specify the List collection type, open the Configure Service Reference dialog and // select the System.Collections.Generic.List type from the Collection type list. Console.WriteLine("See the existing departments and courses."); DisplayDepartmentsAndCourses(); Console.WriteLine(); Console.WriteLine(); // Use some IDs to create // new Department and Course. // The newly created objects will // be then deleted. int departmentID = 100; int courseID = 50; AddNewDepartmentAndCourses(departmentID, courseID); Console.WriteLine("See existing and added."); DisplayDepartmentsAndCourses(); Console.WriteLine(); UpdateDepartmentAndCourses(departmentID, courseID); Console.WriteLine("See existing and updated."); DisplayDepartmentsAndCourses(); Console.WriteLine(); DeleteDepartmentAndCourses(departmentID);
Добавьте в класс следующие методы. Эти методы иллюстрируют следующие действия: вывод объектов, возвращаемых службой, добавление новых объектов, изменение и удаление объектов. Дополнительные сведения см. в комментариях, содержащихся в коде.
Private Sub DisplayDepartmentsAndCourses() Using service = New Service1Client() ' Get all the departments. Dim departments As List(Of Department) = service.GetDepartments() For Each d In departments Console.WriteLine("ID: {0}, Name: {1}", d.DepartmentID, d.Name) ' Get all the courses for each department. ' The reason we are able to access ' the related courses is because the service eagrly loaded the related objects ' (using the System.Data.Objects.ObjectQuery(T).Include method). For Each c In d.Courses.OfType(Of OnlineCourse)() Console.WriteLine(" OnLineCourse ID: {0}, Title: {1}", c.CourseID, c.Title) Next For Each c In d.Courses.OfType(Of OnsiteCourse)() Console.WriteLine(" OnSiteCourse ID: {0}, Title: {1}", c.CourseID, c.Title) Next Next End Using End Sub Private Sub AddNewDepartmentAndCourses(ByVal departmentID As Integer, ByVal courseID As Integer) Using service = New Service1Client() Dim newDepartment As New Department() _ With {.DepartmentID = departmentID, _ .Budget = 13000D, _ .Name = "New Department", _ .StartDate = DateTime.Now _ } Dim newCourse As New OnlineCourse() _ With {.CourseID = courseID, _ .DepartmentID = departmentID, _ .URL = "http://www.fineartschool.net/Trigonometry", _ .Title = "New Onsite Course", _ .Credits = 4 _ } ' Add the course to the department. newDepartment.Courses.Add(newCourse) ' The newly create objects are marked as added, the service will insert these into the store. service.UpdateDepartment(newDepartment) ' Let’s make few more changes to the saved object. ' Since the previous changes have now been persisted, call AcceptChanges to ' reset the ChangeTracker on the objects and mark the state as ObjectState.Unchanged. ' Note, AcceptChanges sets the tracking on, so you do not need to call StartTracking ' explicitly. newDepartment.AcceptChanges() newCourse.AcceptChanges() ' Because the change tracking is enabled ' the following change will set newCourse.ChangeTracker.State to ObjectState.Modified. newCourse.Credits = 6 service.UpdateDepartment(newDepartment) End Using End Sub Private Sub UpdateDepartmentAndCourses(ByVal departmentID As Integer, ByVal courseID As Integer) Using service = New Service1Client() ' Get all the departments. Dim departments As List(Of Department) = service.GetDepartments() ' Use LINQ to Objects to query the departments collection ' for the specific department object. Dim department As Department = departments.Single(Function(d) d.DepartmentID = departmentID) department.Budget = department.Budget - 1000D ' Get the specified course that belongs to the department. ' The reason we are able to access the related course ' is because the service eagrly loaded the related objects ' (using the System.Data.Objects.ObjectQuery(T).Include method). Dim existingCourse As Course = department.Courses.[Single](Function(c) c.CourseID = courseID) existingCourse.Credits = 3 service.UpdateDepartment(department) End Using End Sub Private Sub DeleteDepartmentAndCourses(ByVal departmentID As Integer) Using service = New Service1Client() Dim departments As List(Of Department) = service.GetDepartments() Dim department As Department = departments.Single(Function(d) d.DepartmentID = departmentID) ' When MarkAsDeleted is called, the entity is removed from the collection, ' if we modify the collection over which foreach is looping an exception will be thrown. ' That is why we need to make a copy of the courses collection by ' calling department.Courses.ToList(); Dim courses As List(Of Course) = department.Courses.ToList() For Each c In courses ' Marks each comment for the post as Deleted. ' If another entity have a foreign key relationship with this Course object ' an exception will be thrown during save operation. c.MarkAsDeleted() Next department.MarkAsDeleted() service.UpdateDepartment(department) End Using End Sub
static void DisplayDepartmentsAndCourses() { using (var service = new Service1Client()) { // Get all the departments. List<Department> departments = service.GetDepartments(); foreach (var d in departments) { Console.WriteLine("ID: {0}, Name: {1}", d.DepartmentID, d.Name); // Get all the courses for each department. // The reason we are able to access // the related courses is because the service eagrly loaded the related objects // (using the System.Data.Objects.ObjectQuery(T).Include method). foreach (var c in d.Courses.OfType<OnlineCourse>()) { Console.WriteLine(" OnLineCourse ID: {0}, Title: {1}", c.CourseID, c.Title); } foreach (var c in d.Courses.OfType<OnsiteCourse>()) { Console.WriteLine(" OnSiteCourse ID: {0}, Title: {1}", c.CourseID, c.Title); } } } } static void AddNewDepartmentAndCourses(int departmentID, int courseID) { using (var service = new Service1Client()) { Department newDepartment = new Department() { DepartmentID = departmentID, Budget = 13000.000m, Name = "New Department", StartDate = DateTime.Now }; OnlineCourse newCourse = new OnlineCourse() { CourseID = courseID, DepartmentID = departmentID, URL = "http://www.fineartschool.net/Trigonometry", Title = "New Onsite Course", Credits = 4 }; // Add the course to the department. newDepartment.Courses.Add(newCourse); // The newly create objects are marked as added, the service will insert these into the store. service.UpdateDepartment(newDepartment); // Let’s make few more changes to the saved object. // Since the previous changes have now been persisted, call AcceptChanges to // reset the ChangeTracker on the objects and mark the state as ObjectState.Unchanged. // Note, AcceptChanges sets the tracking on, so you do not need to call StartTracking // explicitly. newDepartment.AcceptChanges(); newCourse.AcceptChanges(); // Because the change tracking is enabled // the following change will set newCourse.ChangeTracker.State to ObjectState.Modified. newCourse.Credits = 6; service.UpdateDepartment(newDepartment); } } static void UpdateDepartmentAndCourses(int departmentID, int courseID) { using (var service = new Service1Client()) { // Get all the departments. List<Department> departments = service.GetDepartments(); // Use LINQ to Objects to query the departments collection // for the specific department object. Department department = departments.Single(d => d.DepartmentID == departmentID); department.Budget = department.Budget - 1000.00m; // Get the specified course that belongs to the department. // The reason we are able to access the related course // is because the service eagrly loaded the related objects // (using the System.Data.Objects.ObjectQuery(T).Include method). Course existingCourse = department.Courses.Single(c => c.CourseID == courseID); existingCourse.Credits = 3; service.UpdateDepartment(department); } } static void DeleteDepartmentAndCourses(int departmentID) { using (var service = new Service1Client()) { List<Department> departments = service.GetDepartments(); Department department = departments.Single(d => d.DepartmentID == departmentID); // When MarkAsDeleted is called, the entity is removed from the collection, // if we modify the collection over which foreach is looping an exception will be thrown. // That is why we need to make a copy of the courses collection by // calling department.Courses.ToList(); List<Course> courses = department.Courses.ToList(); foreach (var c in courses) { // Marks each comment for the post as Deleted. // If another entity have a foreign key relationship with this Course object // an exception will be thrown during save operation. c.MarkAsDeleted(); } department.MarkAsDeleted(); service.UpdateDepartment(department); } }
Проверка службы с помощью консольного клиентского приложения WPF
Создайте приложение WPF. Введите STESchoolModelWPFTest в качестве имени проекта в том же решении, где находится предыдущий проект.
Добавьте ссылку на службу STEASchoolModelService. Для добавления ссылки на службу щелкните правой кнопкой мыши папку ссылок в обозревателе решений и выберите Добавить ссылку на службу.
По умолчанию WCF создает прокси-объект, возвращающий коллекцию IEnumerable. Поскольку в службе STESchoolModelService метод GetDepartments возвращает List, следует сконфигурировать службу так, чтобы задать соответствующий тип возврата.
Щелкните правой кнопкой мыши имя службы (ServiceReference1) и выберите Настроить ссылку на службу…. В диалоговом окне «Настроить ссылку на службу» выберите тип System.Collections.Generic.List из списка Тип коллекции.
Добавьте ссылку на проект STESchoolModelTypes .
Откройте файл app.config и добавьте в файл строку подключения. Откройте файл app.config проекта STESchoolModel и скопируйте элемент connectionStrings, чтобы добавить его в качестве дочернего элемента configuration в файле Web.config.
Теперь можно удалить файл app.config проекта STESchoolModel , потому что он не используется.
По умолчанию шаблон проекта добавляет к проекту файл MainWindow.xaml и соответствующий файл фонового кода.
Откройте файл MainWindow.xaml и замените код XAML, созданный по умолчанию, кодом XAML, задающим окно STESchoolModelWPFTest в WPF. Дополнительные сведения см. в комментариях, содержащихся в коде.
<Window x:Class="STESchoolModelWPFTest.MainWindow" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="508" Width="919" Loaded="Window_Loaded"> <!-- The code begind code sets the departmentsItemsGrid to the root of the object graph.--> <Grid Name="departmentsItemsGrid"> <!-- comboBoxDepartment points to the root of the graph, that is why the Path is not specified--> <ComboBox DisplayMemberPath="DepartmentID" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="true" Height="23" Margin="122,12,198,0" Name="comboBoxDepartment" VerticalAlignment="Top"/> <!-- listViewItems Path is set to Courses because it is bound to Department.Courses.--> <ListView ItemsSource="{Binding Path=Courses}" Name="listViewItems" Margin="34,46,34,50" > <ListView.View> <GridView AllowsColumnReorder="False" ColumnHeaderToolTip="Courses" > <GridViewColumn DisplayMemberBinding="{Binding Path=CourseID}" Header="CourseID" Width="70"/> <!--The TextBox controls are embedded in the two of the following columns. This is done to enable editing in the ListView control. --> <GridViewColumn Header="Title" Width="100"> <GridViewColumn.CellTemplate> <DataTemplate> <TextBox Height="25" Width="100" Text="{Binding Path=Title}" /> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Header="Credits" Width="100" > <GridViewColumn.CellTemplate> <DataTemplate> <TextBox Height="25" Width="100" Text="{Binding Path=Credits}" /> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> </GridView> </ListView.View> </ListView> <Label Height="28" Margin="34,12,0,0" Name="departmentLabel" VerticalAlignment="Top" HorizontalAlignment="Left" Width="93">Department:</Label> <!--When the Save and Close button is clicked all the objects will be sent to the service where all the updated objects will be saved to the database. --> <Button Height="23" HorizontalAlignment="Right" Margin="0,0,34,12" Name="buttonClose" VerticalAlignment="Bottom" Width="127" Click="buttonClose_Click">Save and Close</Button> </Grid> </Window>
Откройте файл MainWindow.xaml.cs (или .vb) и замените код, созданный по умолчанию, следующим кодом (дополнительные объяснения см. в комментариях, содержащихся в коде).
Class MainWindow Dim departments As List(Of Department) Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded Using service = New Service1Client() ' Set the parent of of your data bound controls to the root of the graph. ' In the xaml page the appropriate paths should be set on each data bound control. ' For the comboBoxDepartment it is empty because it is bound to Departments (which is root). ' For the listViewItems it is set to Courses because it is bound to Department.Courses. ' Note, that the TextBox controls are embedded in the two of the columns in the listViewItems. ' This is done to enable editing in the ListView control. departments = service.GetDepartments() Me.departmentsItemsGrid.DataContext = departments End Using End Sub Private Sub buttonSave_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles buttonSave.Click Using service = New Service1Client() ' Save all the departments and their courses. For Each department In departments service.UpdateDepartment(department) ' Call AcceptChanges on all the objects ' to resets the change tracker and set the state of the objects to Unchanged. department.AcceptChanges() For Each course In department.Courses course.AcceptChanges() Next Next End Using End Sub Private Sub buttonClose_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles buttonClose.Click ' Close the form. Me.Close() End Sub End Class
public partial class MainWindow : Window { private List<Department> departments; public MainWindow() { InitializeComponent(); } private void Window_Loaded(object sender, RoutedEventArgs e) { using (var service = new Service1Client()) { // Set the parent of of your data bound controls to the root of the graph. // In the xaml page the appropriate paths should be set on each data bound control. // For the comboBoxDepartment it is empty because it is bound to Departments (which is root). // For the listViewItems it is set to Courses because it is bound to Department.Courses. // Note, that the TextBox controls are embedded in the two of the columns in the listViewItems. // This is done to enable editing in the ListView control. departments = service.GetDepartments(); this.departmentsItemsGrid.DataContext = departments; } } private void buttonSave_Click(object sender, RoutedEventArgs e) { using (var service = new Service1Client()) { // Save all the departments and their courses. foreach (var department in departments) { service.UpdateDepartment(department); // Call AcceptChanges on all the objects // to resets the change tracker and set the state of the objects to Unchanged. department.AcceptChanges(); foreach (var course in department.Courses) course.AcceptChanges(); } } } private void buttonClose_Click(object sender, RoutedEventArgs e) { //Close the form. this.Close(); } }
См. также
Основные понятия
Работа с сущностями с самостоятельным отслеживанием
Сериализация объектов (платформа Entity Framework)
Построение многоуровневых приложений (платформа Entity Framework)