Share via


Exemplarische Vorgehensweise: Serialisieren von Entitäten mit Selbstnachverfolgung (Entity Framework)

Die exemplarische Vorgehensweise in diesem Thema veranschaulicht ein Szenario, in dem ein WCF-Dienst (Windows Communication Foundation) eine Reihe von Vorgängen verfügbar macht, die Entitätsdiagramme zurückgeben. Anschließend wird das Diagramm von einer Clientanwendung bearbeitet. Die Änderungen werden an einen Dienstvorgang gesendet, der die Updates überprüft und mithilfe von Entity Framework in einer Datenbank speichert. Weitere Informationen finden Sie unter Arbeiten mit Entitäten mit Selbstnachverfolgung.

In der Regel soll das Modellprojekt von dem Projekt getrennt werden, das die Entitätstypen mit Selbstnachverfolgung enthält. Auf diese Weise muss der Client lediglich das Entitätstypenprojekt beinhalten.

Eine Möglichkeit für eine solche Isolation besteht darin, die Entitätstypen mit Selbstnachverfolgung vom Modell zu trennen und die Vorlage, die die Entitätstypen generiert, in eine separate Klassenbibliothek zu verschieben. Um auf die Metadaten zugreifen zu können, muss die Vorlage für Entitäten mit Selbstnachverfolgung den Speicherort der EDMX-Datei enthalten. Wenn Sie Vorlagen aus dem ursprünglichen Projekt in andere Projekte verschieben, müssen Sie die Vorlagendateien in einem Editor öffnen und die inputFile-Zeichenfolge zum entsprechenden Speicherort der EDMX-Datei ändern. Weitere Informationen zum Arbeiten mit Vorlagen finden Sie unter ADO.NET Self-Tracking Entity Template.

Eine andere Möglichkeit, die Entitätstypen vom Modell zu trennen, besteht darin, die Vorlagendateien im ursprünglichen Projekt zu belassen, die Codegenerierung für die Vorlagen jedoch zu deaktivieren. Erstellen Sie eine Verknüpfung zu den Vorlagen eines anderen Projekts, damit der Code dort und nicht im ursprünglichen Projekt generiert wird. Wenn Sie einem Projekt eine Verknüpfung als Element hinzufügen, wird der tatsächliche Inhalt des Elements an dem Ort gewartet, der im ursprünglichen Projekt angegeben wurde. Diese Methode, die Entitätstypen vom Modell zu trennen, wird in dieser exemplarischen Vorgehensweise veranschaulicht.

Diese exemplarische Vorgehensweise umfasst die folgenden Aktionen:

  • Erstellen des Klassenbibliotheksprojekts, das das auf "School" beruhende Modell enthält.

  • Verwendet die Vorlage für den ADO.NET-Entitäts-Generator mit Selbstnachverfolgung, um die Entitätstypen, den typisierten ObjectContext und eine Erweiterungsklasse zu generieren, die überladene ApplyChanges-Methoden enthält.

  • Erstellt das Klassenbibliotheksprojekt, das mit der Vorlage für Entitätstypen mit Selbstnachverfolgung verknüpft ist, die im ersten Projekt erstellt wurde.

  • Erstellt den WCF-Dienst, der einen Satz von Vorgängen verfügbar macht, die Entitätsdiagramme zurückgeben und mithilfe von Entity Framework auf dem Client vorgenommene Änderungen in der Datenbank durchführt.

  • Erstellt die Clientanwendungen (Konsole und Windows Presentation Foundation [WPF]), mit denen Diagramme bearbeitet und die Änderungen mithilfe der im WCF-Dienst verfügbar gemachten Vorgänge gesendet werden.

Ee789839.note(de-de,VS.100).gifHinweis:
Sie können STESchoolModelExample auf der Entity Framework Documentation Samples-Website in der MSDN Code Gallery herunterladen.

So erstellen Sie das Klassenbibliotheksprojekt, das die Entitäten mit Selbstnachverfolgung und die Objektkontextklassen enthält

  1. Erstellen Sie ein neues Klassenbibliotheksprojekt. Geben Sie für den Projekt- und den Projektmappennamen STESchoolModel ein.

  2. Entfernen Sie die Standardquellcodedatei, die dem Projekt hinzugefügt wurde.

  3. Generieren Sie mithilfe des Assistenten für Entity Data Model ein Modell auf Grundlage der Department-, Course-, OnlineCourse und OnsiteCourse-Tabellen in der Datenbank School. Weitere Informationen finden Sie unter Modell "School".

  4. Öffnen Sie die EDMX-Datei in ADO.NET Entity Data Model Designer (Entity Designer).

  5. Befolgen Sie die Anweisungen zur Vererbungszuordnung im Thema Walkthrough: Mapping Inheritance - Table-per-Type.

  6. Klicken Sie mit der rechten Maustaste auf einen leeren Bereich der Entity Designer-Oberfläche, zeigen Sie auf Neues Codegenerierungselement hinzufügen, und wählen Sie anschließend ADO.NET-Entitäts-Generator mit Selbstnachverfolgung aus. Ändern Sie den Standardvorlagennamen zu SchoolModel.

    Ee789839.note(de-de,VS.100).gifHinweis:
    Wenn dem Projekt die Vorlagendateien hinzugefügt werden, fordert Sie eine Sicherheitswarnung möglicherweise dazu auf, den Vorgang nur dann anzunehmen, wenn Sie der Quelle der Vorlage vertrauen.Klicken Sie auf Annehmen.

  7. Dem Projekt werden die Ordner SchoolModel.Context.tt und SchoolModel.tt hinzugefügt. Im Ordner SchoolModel.Context.tt befinden sich zwei Dateien, die den typisierten ObjectContext und die Erweiterungsklasse definieren, die überladene ApplyChanges-Methoden enthält. Im Ordner SchoolModel.tt befinden sich Dateien, die Entitätstypen definieren, sowie eine Hilfsklasse, die die von den Entitäten mit Selbstnachverfolgung verwendete Änderungsnachverfolgungslogik enthält.

    Die nächsten zwei Schritte veranschaulichen das Deaktivieren der Codegenerierung in diesem Projekt. Die Codegenerierung wird zu einem späteren Zeitpunkt für die Typen in der Klassenbibliothek STESchoolModelTypes und für den Objektkontext im STESchoolModelService aktiviert.

  8. Wählen Sie SchoolModel.tt aus. Löschen Sie im Fenster Eigenschaften den Wert TextTemplatingFileGenerator der CustomTool-Eigenschaft. Löschen Sie die Dateien im Ordner SchoolModel.tt.

  9. Klicken Sie auf SchoolModel.Context.tt. Löschen Sie im Fenster Eigenschaften den Wert der CustomTool-Eigenschaft. Löschen Sie die Dateien unter dem Ordner SchoolModel.Context.tt.

    Wenn Sie mit dem Visual Basic-Projekt arbeiten, müssen Sie im Projektmappen-Explorer möglicherweise auf Alle Dateien anzeigen klicken, um alle Dateien im Projekt anzuzeigen.

  10. Kompilieren Sie das Projekt.

So erstellen Sie das Klassenbibliotheksprojekt, das mit der Vorlage für die Typen mit Selbstnachverfolgung verknüpft ist

  1. Erstellen Sie in der gleichen Projektmappe wie der des vorherigen Projekts ein neues Klassenbibliotheksprojekt mit dem Namen STESchoolModelTypes.

  2. Entfernen Sie die Standardquellcodedatei, die dem Projekt hinzugefügt wurde.

  3. Fügen Sie der Datei SchoolModel.tt einen Link hinzu, damit die Entitätstypen mit Selbstnachverfolgung in dieser Projektmappe generiert werden. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf STESchoolModelTypes, klicken Sie auf Hinzufügen, und klicken Sie dann auf Vorhandenes Element.

  4. Wechseln Sie im Dialogfeld Vorhandenes Element hinzufügen zum STESchoolModel-Projekt, und klicken Sie auf SchoolModel.tt (drücken Sie nicht die EINGABETASTE). Wählen Sie in der Liste Hinzufügen den Befehl Als Link hinzufügen aus.

  5. Fügen Sie einen Verweis auf die System.Runtime.Serialization-Bibliothek hinzu. Diese Bibliothek wird für die WCF-Attribute DataContract und DataMember benötigt, die für die serialisierbaren Entitätstypen verwendet werden.

  6. Kompilieren Sie das Projekt.

So erstellen und konfigurieren Sie das WCF-Dienstanwendungsprojekt

  1. Erstellen Sie in der gleichen Projektmappe wie der des vorherigen Projekts ein WCF-Dienstanwendungsprojekt mit dem Namen STESchoolModelService.

  2. Fügen Sie einen Verweis auf System.Data.Entity.dll hinzu.

  3. Fügen Sie einen Verweis auf die STESchoolModel- und STESchoolModelTypes-Projekte hinzu.

  4. Fügen Sie in die Datei SchoolModel.Context.tt einen Link ein, damit die Kontexttypen in dieser Projektmappe generiert werden. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf STESchoolModelService, klicken Sie auf Hinzufügen, und klicken Sie dann auf Vorhandenes Element.

  5. Wechseln Sie im Dialogfeld Vorhandenes Element hinzufügen zum STESchoolModel-Projekt, und klicken Sie auf SchoolModel.Context.tt (drücken Sie nicht die EINGABETASTE). Wählen Sie in der Liste Hinzufügen den Befehl Als Link hinzufügen aus.

  6. Geben Sie im Eigenschaftenfenster für die Datei SchoolModel.Context.tt in der Custom Tool Namespace-Eigenschaft den Wert STESchoolModelService ein. Damit wird der Objektkontexttyp, wie erforderlich, dem gleichen Namespace hinzugefügt wie der Namespace für die Entitätstypen mit Selbstnachverfolgung.

  7. (Nur Visual Basic) Fügen Sie den aus der Datei SchoolModel.Context.tt generierten Quelldateien Import STESchoolModelTypes hinzu. Öffnen Sie die Datei SchoolModel.Context.tt, und suchen Sie die Zeichenfolge Imports System. Fügen Sie im Anschluss an andere Importvorgänge Import STESchoolModelTypes hinzu. Die generierten Quelldateien beinhalten diesen Namespace.

  8. Fügen Sie der Datei Web.config die Verbindungszeichenfolge hinzu, damit die Entity Framework -Laufzeit die Metadaten finden kann. Öffnen Sie die Datei App.Config des Projekts STESchoolModel. Kopieren Sie das connectionStrings-Element, und fügen Sie es anschließend als untergeordnetes Element des configuration-Elements der Datei Web.config hinzu.

  9. Öffnen Sie die Dienstschnittstellendatei. Standardmäßig trägt die Datei den Namen IService1.

  10. Fügen Sie den Namespace hinzu, in dem die Entitäten mit Selbstnachverfolgung definiert sind: STESchoolModelTypes.

  11. Ersetzen Sie die Dienstschnittstellendefinition durch den folgenden Code:

    <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();
    }
    
  12. Öffnen Sie den Dienstquellcode. In der Standardeinstellung trägt die Datei den Namen Service1.srv.cs oder Service1.srv.vb.

  13. Fügen Sie den Namespace hinzu, in dem die Entitäten mit Selbstnachverfolgung definiert sind: STESchoolModelTypes.

  14. (Nur Visual Basic) Fügen Sie Imports STESchoolModelService.STESchoolModelTypes der Datei Service1.srv.cs hinzu.

  15. Ersetzen Sie die Dienstklassendefinition durch den folgenden Code:

Ee789839.Important(de-de,VS.100).gif Hinweis:
Vor dem Übernehmen der Änderungen sollte stets eine Validierung des aktualisierten Objekts durchgeführt werden.

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();
        }
    }

}

So testen Sie den Dienst mit einer Konsolenclientanwendung

  1. Erstellen Sie eine Konsolenanwendung. Geben Sie in der gleichen Projektmappe wie der des vorherigen Projekts STESchoolModelTest als Projektnamen ein.

  2. Fügen Sie einen Verweis auf den STEASchoolModelService-Dienst hinzu. Um im Projektmappen-Explorer einen Verweis auf den Dienst hinzuzufügen, klicken Sie mit der rechten Maustaste auf den Verweisordner, und wählen Sie anschließend Dienstverweis hinzufügen aus.

    In der Standardeinstellung wird von WCF ein Proxy generiert, der die IEnumerable-Auflistung zurückgibt. Da die GetDepartments-Methode von STESchoolModelService List zurückgibt, muss der Dienst so konfiguriert werden, dass der entsprechende Rückgabetyp angegeben wird.

  3. Klicken Sie mit der rechten Maustaste auf den Dienstnamen (ServiceReference1), und wählen Sie anschließend Dienstverweis konfigurieren… aus. Wählen Sie im Dialogfeld Dienstverweis konfigurieren aus der Liste Auflistungstyp den Typ System.Collections.Generic.List aus.

  4. Fügen Sie einen Verweis auf das STESchoolModelTypes -Projekt hinzu.

  5. Öffnen Sie die Datei app.config, und fügen Sie die Verbindungszeichenfolge in die Datei ein. Öffnen Sie die Datei app.config des STESchoolModel-Projekts, kopieren Sie das connectionStrings-Element, und fügen Sie es als untergeordnetes Element des configuration-Elements in die Datei Web.config ein.

  6. Öffnen Sie die Datei, die die Hauptfunktion enthält. Fügen Sie die folgenden Namespaces ein: den STESchoolModelTest.ServiceReference1-Namespace und den STESchoolModelTypes-Namespace (in dem die Typen mit Selbstnachverfolgung definiert sind).

  7. Fügen Sie den folgenden Code in die Hauptfunktion ein. Der Code enthält Funktionsaufrufe der Methoden, die im nächsten Schritt definiert werden.

    ' 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);
    
  8. Fügen Sie der Klasse die folgenden Methoden hinzu. Anhand der Methoden wird beschrieben, wie die folgenden Aktionen durchgeführt werden: Anzeigen der vom Dienst zurückgegebenen Objekte, Hinzufügen neuer Objekte, Aktualisieren von Objekten und Löschen von Objekten. Weitere Informationen finden Sie in den Codekommentaren.

    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);
        }
    }
    

So testen Sie den Dienst mit einer WPF-Clientanwendung

  1. Erstellen Sie eine WPF-Anwendung. Geben Sie in der gleichen Projektmappe wie der des vorherigen Projekts als Projektnamen STESchoolModelWPFTest ein.

  2. Fügen Sie einen Verweis auf den STEASchoolModelService-Dienst hinzu. Um im Projektmappen-Explorer einen Verweis auf den Dienst hinzuzufügen, klicken Sie mit der rechten Maustaste auf den Verweisordner, und wählen Sie anschließend Dienstverweis hinzufügen aus.

    In der Standardeinstellung wird von WCF ein Proxy generiert, der die IEnumerable-Auflistung zurückgibt. Da die GetDepartments-Methode von STESchoolModelService List zurückgibt, muss der Dienst so konfiguriert werden, dass der entsprechende Rückgabetyp angegeben wird.

  3. Klicken Sie mit der rechten Maustaste auf den Dienstnamen (ServiceReference1), und wählen Sie anschließend Dienstverweis konfigurieren… aus. Wählen Sie im Dialogfeld Dienstverweis konfigurieren aus der Liste Auflistungstyp den Typ System.Collections.Generic.List aus.

  4. Fügen Sie einen Verweis auf das STESchoolModelTypes -Projekt hinzu.

  5. Öffnen Sie die Datei app.config, und fügen Sie die Verbindungszeichenfolge in die Datei ein. Öffnen Sie die Datei app.config des STESchoolModel-Projekts, kopieren Sie das connectionStrings-Element, und fügen Sie es als untergeordnetes Element des configuration-Elements in die Datei Web.config ein.

    Die Datei app.config für das Projekt STESchoolModel kann nun gelöscht werden, da sie niemals verwendet wird.

    In der Standardeinstellung fügt die Projektvorlage dem Projekt die Datei MainWindow.xaml und den entsprechenden Code der Datei hinzu.

  6. Öffnen Sie die Datei MainWindow.xaml, und ersetzen Sie anschließend den Standard-XAML-Code durch das XAML, das das Fenster STESchoolModelWPFTest in WPF definiert. Weitere Informationen finden Sie in den Codekommentaren.

    <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>
    
  7. Öffnen Sie die Datei MainWindow.xaml.cs (oder .vb), und ersetzen Sie anschließend den Standardcode durch folgenden Code (weitere Informationen finden Sie in den Codekommentaren).

    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();
        }
    }
    

Siehe auch

Konzepte

Arbeiten mit Entitäten mit Selbstnachverfolgung
Serialisieren von Objekten (Entity Framework)
Erstellen von N-Tier-Anwendungen (Entity Framework)

Weitere Ressourcen

ADO.NET Self-Tracking Entity Template