Exemplarische Vorgehensweise: Zuordnen einer Entität zu gespeicherten Prozeduren (Entity Data Model-Tools)

In diesem Thema wird gezeigt, wie mit dem ADO.NET Entity Data Model-Designer (Entity Designer) die Einfüge-, Aktualisierungs- und Löschvorgänge eines Entitätstyps gespeicherten Prozeduren zugeordnet werden. Einfüge-, Aktualisierungs- und Löschvorgänge eines Entitätstyps können SQL-Anweisungen, die vom System automatisch erzeugt werden (Standard), oder durch den Entwickler angegebene gespeicherte Prozeduren verwenden. Der zum Erstellen, Aktualisieren und Löschen von Entitäten verwendete Anwendungscode ändert sich durch die Verwendung gespeicherter Prozeduren zur Aktualisierung der Datenbank nicht.

In dieser exemplarischen Vorgehensweise ordnen Sie zwei Entitätstypen (im konzeptionellen Modell) gespeicherten Prozeduren (im Speichermodell) zu, indem Sie die in der CourseManager-Anwendung (weitere Informationen finden Sie im Abschnitt "Erforderliche Komponenten" weiter unten in diesem Thema) verwendete EDMX-Datei ändern. Außerdem schreiben Sie Code, mit dem Entitätstypen eingefügt, aktualisiert und gelöscht werden.

Cc716679.note(de-de,VS.100).gifHinweis:
Wenn Sie nicht alle drei Einfüge-, Aktualisierungs- und Löschvorgänge eines Entitätstyps gespeicherten Prozeduren zuordnen, schlagen die nicht zugeordneten Vorgänge bei der Ausführung zur Laufzeit fehl, und UpdateException wird ausgelöst.

Erforderliche Komponenten

Zum Durchführen dieser exemplarischen Vorgehensweise müssen Sie die CourseManager-Anwendung erstellen. Weitere Informationen und Anweisungen finden Sie im Entity Framework-Schnellstart. Nachdem Sie diese Anwendung erstellt haben, ändern Sie die zugehörige EDMX-Datei, indem Sie zwei Entitätstypen gespeicherten Prozeduren zuordnen.

Cc716679.note(de-de,VS.100).gifHinweis:
Da die CourseManager-Anwendung für viele der exemplarischen Vorgehensweisen in dieser Dokumentation als Ausgangspunkt dient, wird empfohlen, für diese exemplarische Vorgehensweise eine Kopie der CourseManager-Anwendung zu verwenden und nicht den Originalcode zu bearbeiten.

In dieser exemplarischen Vorgehensweise wird davon ausgegangen, dass Sie über grundlegende Kenntnisse in Visual Studio, .NET Framework und entweder Visual C#- oder Visual Basic-Programmierung verfügen.

Zuordnen der "Person"-Entität zu gespeicherten Prozeduren

Wenn Sie den Einfügevorgang einer Entität einer gespeicherten Prozedur zuordnen und der Server den Primärschlüsselwert für die eingefügte Zeile erstellt, müssen Sie diesen Wert wieder der Schlüsseleigenschaft der Entität zuordnen. In diesem Beispiel gibt die gespeicherte Prozedur InsertPerson den neu erstellten Primärschlüssel als Teil ihres Resultsets zurück. Der Primärschlüssel wird dem Entitätsschlüssel (PersonID) mithilfe der Funktion <Result Binding hinzufügen> des Entity Designers zugeordnet.

Cc716679.note(de-de,VS.100).gifHinweis:
Wenn Sie einen Einfüge-, Aktualisierungs- oder Löschvorgang einer gespeicherten Prozedur zuordnen, die einen Ganzzahlwert als Ausgabeparameter zurückgibt, wird das Kontrollkästchen Parameter für betroffene Zeilen aktiviert.Wenn das Kontrollkästchen für einen Parameter aktiviert ist und beim Aufruf des Vorgangs der Wert 0 (null) zurückgegeben wird, wird OptimisticConcurrencyException ausgelöst.

So ordnen Sie die Person-Entität gespeicherten Prozeduren zu

  1. Öffnen Sie in Visual Studio die CourseManager-Projektmappe.

  2. Doppelklicken Sie im Projektmappen-Explorer auf die Datei School.edmx.

    Die Datei School.edmx wird im ADO.NET Entity Data Model-Designer (Entity Designer) geöffnet.

  3. Klicken Sie mit der rechten Maustaste auf den Person-Entitätstyp, und wählen Sie Zuordnung der gespeicherten Prozedur aus.

    Die Mappings der gespeicherten Prozedur werden im Fenster Zuordnungsdetails angezeigt.

  4. Klicken Sie auf <Insert Function auswählen>.

    Das Feld wird zu einer Dropdownliste mit den gespeicherten Prozeduren im Speichermodell, die Entitätstypen im konzeptionellen Modell zugeordnet werden können.

  5. Wählen Sie in der Dropdownliste den Eintrag InsertPerson aus.

    Es werden Standardzuordnungen zwischen Parametern gespeicherter Prozeduren und Entitätseigenschaften angezeigt. Pfeile geben die Zuordnungsrichtung an: Eigenschaftswerte sind Parametern gespeicherter Prozeduren zugeordnet.

  6. Klicken Sie auf <Result Binding hinzufügen>.

    Das Feld wird bearbeitbar.

  7. Geben Sie NewPersonID ein. Das ist der Name des von der gespeicherten Prozedur InsertPerson zurückgegebenen Parameters. Drücken Sie die EINGABETASTE.

    Standardmäßig wird NewPersonID dem Entitätsschlüssel PersonID zugeordnet. Ein Pfeil gibt die Mappingrichtung an: Der Wert der Ergebnisspalte ist der Eigenschaft zugeordnet.

  8. Klicken Sie auf <Update Function auswählen>, und wählen Sie UpdatePerson in der resultierenden Dropdownliste aus.

    Es werden Standardmappings zwischen Parametern gespeicherter Prozeduren und Entitätseigenschaften angezeigt.

  9. Klicken Sie auf <Delete Function auswählen>, und wählen Sie DeletePerson in der resultierenden Dropdownliste aus.

    Es werden Standardmappings zwischen Parametern gespeicherter Prozeduren und Entitätseigenschaften angezeigt.

Die Einfüge-, Aktualisierungs- und Löschvorgänge des Entitätstyps Person werden nun gespeicherten Prozeduren zugeordnet.

Zuordnen der OfficeAssignment-Entität zu gespeicherten Prozeduren

In diesem Beispiel wird der OfficeAssignment-Entitätstyp gespeicherten Prozeduren zugeordnet. Bei dieser Zuordnung wird die Option Originalwert verwenden für den Aktualisierungsvorgang verwendet, um eine einfache Möglichkeit zur Überprüfung der Parallelität im Anwendungscode zu erhalten.

So ordnen Sie die "OfficeAssignment"-Entität gespeicherten Prozeduren zu

  1. Klicken Sie mit der rechten Maustaste auf den OfficeAssignment-Entitätstyp, und wählen Sie Stored Procedure Mapping aus.

    Die Mappings der gespeicherten Prozedur werden im Fenster Zuordnungsdetails angezeigt.

  2. Klicken Sie auf <Insert Function auswählen>, und wählen Sie InsertOfficeAssignment in der resultierenden Dropdownliste aus.

    Es werden Standardmappings zwischen Parametern gespeicherter Prozeduren und Entitätseigenschaften angezeigt.

  3. Klicken Sie auf <Result Binding hinzufügen>.

    Das Feld wird bearbeitbar.

  4. Geben Sie Timestamp ein.

  5. Klicken Sie auf das leere Feld in der Property/Value-Spalte neben Timestamp.

    Das Feld wird zu einer Dropdownliste mit Eigenschaften, denen der von der gespeicherten Prozedur InsertOfficeAssignment zurückgegebene Wert zugeordnet werden kann.

  6. Wählen Sie in der Dropdownliste den Eintrag Timestamp aus.

  7. Klicken Sie auf <Update Function auswählen>, und wählen Sie UpdateOfficeAssignment in der resultierenden Dropdownliste aus.

    Es werden Standardmappings zwischen Parametern gespeicherter Prozeduren und Entitätseigenschaften angezeigt. Neben jeder zugeordneten Eigenschaft in der Spalte Originalwert verwenden wird ein Kontrollkästchen angezeigt.

  8. Klicken Sie auf das leere Feld in der Spalte Eigenschaft, die dem Parameter OrigTimestamp entspricht, und wählen Sie Timestamp in der resultierenden Dropdownliste aus.

    Der Entity Designer hat dieses Standardmapping nicht vorgenommen, da der Parametername nicht genau mit dem Eigenschaftennamen übereinstimmte.

  9. Aktivieren Sie das Kontrollkästchen in der Spalte Originalwert verwenden, das der Timestamp-Eigenschaft entspricht.

    Wenn versucht wird, eine Aktualisierung durchzuführen, wird der ursprünglich aus der Datenbank ausgelesene Wert der Timestamp-Eigenschaft beim Zurückschreiben der Daten in die Datenbank verwendet. Wenn der Wert nicht mit dem Wert in der Datenbank übereinstimmt, wird eine OptimisticConcurrencyException ausgelöst.

  10. Klicken Sie auf <Result Binding hinzufügen>.

    Das Feld wird bearbeitbar.

  11. Ersetzen Sie <Result Binding hinzufügen> durch Timestamp.

  12. Klicken Sie auf das leere Feld in der Property/Value-Spalte neben Timestamp.

    Das Feld wird zu einer Dropdownliste mit Eigenschaften, denen die von der gespeicherten Prozedur UpdateOfficeAssignment zurückgegebene Ergebnisspalte zugeordnet werden kann.

  13. Wählen Sie in der Dropdownliste den Eintrag Timestamp aus.

  14. Klicken Sie auf <Delete Function auswählen>, und wählen Sie DeleteOfficeAssignment in der resultierenden Dropdownliste aus.

    Es werden Standardmappings zwischen Parametern gespeicherter Prozeduren und Entitätseigenschaften angezeigt.

Die Einfüge-, Aktualisierungs- und Löschvorgänge des Entitätstyps OfficeAssignment werden nun gespeicherten Prozeduren zugeordnet.

Erstellen der Benutzeroberfläche

Im nächsten Schritt fügen Sie der Anwendung "CourseManager" zwei Formulare hinzu. Ein Formular stellt eine Schnittstelle zum Anzeigen und Aktualisieren von Kursleiterinformationen bereit. Das andere Formular stellt eine Schnittstelle zum Anzeigen und Aktualisieren von Büroaufgaben zur Verfügung.

So erstellen Sie die Benutzeroberfläche

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das CourseManager-Projekt, zeigen Sie auf Hinzufügen, und wählen Sie die Option Neues Element aus.

    Das Dialogfeld Neues Element hinzufügen wird angezeigt.

  2. Wählen Sie Windows Form aus, legen Sie den Namen des Formulars auf InstructorViewer.vb oder InstructorViewer.cs fest, und klicken Sie auf Hinzufügen.

    Dem Projekt wird ein neues Formular hinzugefügt, und das Formular wird im Formular-Designer geöffnet. Der Name des Formulars wird auf InstructorViewer festgelegt, und der Text wird auf InstructorViewer festgelegt.

  3. Ziehen Sie ein DataGridView-Steuerelement von der Toolbox auf das Formular, und legen Sie den Namen im Fenster Eigenschaften auf instructorGridView fest.

  4. Ziehen Sie ein Button-Steuerelement von der Toolbox auf das Formular. Legen Sie für den Namen updateInstructor und für den Text Update Instructor fest.

  5. Ziehen Sie ein weiteres Button-Steuerelement von der Toolbox auf das Formular. Legen Sie für den Namen viewOffices und für den Text View Offices fest.

  6. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das CourseManager-Projekt, zeigen Sie auf Hinzufügen, und wählen Sie die Option Neues Element aus.

    Das Dialogfeld Neues Element hinzufügen wird angezeigt.

  7. Wählen Sie Windows Form aus, legen Sie den Namen des Formulars auf OfficeViewer.vb oder OfficeViewer.cs fest, und klicken Sie auf Hinzufügen.

    Dem Projekt wird ein neues Formular hinzugefügt, und das Formular wird im Formular-Designer geöffnet. Der Name des Formulars wird auf OfficeViewer festgelegt, und der Text wird auf OfficeViewer festgelegt.

  8. Ziehen Sie ein ComboBox-Steuerelement von der Toolbox auf das Formular, und legen Sie seinen Namen auf instructorList fest.

  9. Ziehen Sie ein TextBox-Steuerelement von der Toolbox auf das Formular, und legen Sie seinen Namen auf officeLocation fest.

  10. Ziehen Sie ein Button-Steuerelement von der Toolbox auf das Formular. Legen Sie für den Namen updateOffice und für den Text Update Office fest.

  11. Doppelklicken Sie im Projektmappen-Explorer auf CourseViewer.vb oder CourseViewer.cs.

    Die Entwurfsansicht des CourseViewer-Formulars wird angezeigt.

  12. Ziehen Sie ein Button-Steuerelement von der Toolbox auf das Formular.

  13. Legen Sie im Fenster Eigenschaften die Name-Eigenschaft des Button auf viewInstructors und die Text-Eigenschaft auf View Instructors fest.

  14. Doppelklicken Sie auf das Button-Steuerelement viewInstructors.

    Die CodeBehind-Datei für das CourseViewer-Formular wird geöffnet.

  15. Fügen Sie dem viewInstructors_Click-Ereignishandler folgenden Code hinzu:

    Dim instructorViewer As New InstructorViewer()
    instructorViewer.Visible = True
    
    InstructorViewer instructorViewer = new InstructorViewer();
    instructorViewer.Visible = true;
    
  16. Kehren Sie zur Entwurfsansicht des InstructorViewer-Formulars zurück.

  17. Doppelklicken Sie auf das Button-Steuerelement viewOffices.

    Die CodeBehind-Datei für Form2 wird geöffnet.

  18. Fügen Sie dem viewOffices_Click-Ereignishandler folgenden Code hinzu:

    Dim officeViewer As New OfficeViewer()
    officeViewer.Visible = True
    
    OfficeViewer officeViewer = new OfficeViewer();
    officeViewer.Visible = true;
    

Die Benutzeroberfläche ist jetzt vollständig.

Anzeigen und Aktualisieren von Kursleiterinformationen

In diesem Verfahren fügen Sie dem InstructorViewer-Formular Code hinzu, mit dem Kursleiterinformationen angezeigt und aktualisiert werden können. Genauer gesagt erfüllt der Code folgende Aufgaben:

  • Binden des DataGridView an eine Abfrage, die Informationen über Person-Typen zurückgibt, die Kursleiter sind. Weitere Informationen über das Binden von Objekten an Steuerelemente finden Sie unter Binding Objects to Controls (Entity Framework).

  • Speichern aller Änderungen (Einfügungen, Aktualisierungen oder Löschungen) im DataGridView-Steuerelement in der Datenbank.

  • Schreiben von Daten in die Datenbank mithilfe der zuvor zugeordneten gespeicherten Prozeduren, wenn SaveChanges() im updateInstructor_Click-Ereignishandler aufgerufen wird.

So zeigen Sie Kursleiterinformationen an und aktualisieren diese

  1. Doppelklicken Sie auf das InstructorViewer-Formular, während das InstructorViewer-Formular im Formular-Designer angezeigt wird.

    Die CodeBehind-Datei für das InstructorViewer-Formular wird geöffnet.

  2. Fügen Sie die folgenden using- (C#) bzw. Imports-Anweisungen (Visual Basic) hinzu:

    Imports System.Data.Objects
    Imports System.Data.Objects.DataClasses
    
    using System.Data.Objects;
    using System.Data.Objects.DataClasses;
    
  3. Fügen Sie eine Eigenschaft zur InstructorViewer-Klasse hinzu, die den Objektkontext darstellt:

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities
    
    // Create an ObjectContext instance based on SchoolEntity.
    private SchoolEntities schoolContext;
    
  4. Fügen Sie Code zum InstructorViewer_Load-Ereignishandler zur Initialisierung des Objektkontexts hinzu, und legen Sie eine Abfrage als Datenquelle für das DataGridView-Steuerelement fest, die alle Person-Typen zurückgibt, deren HireDate nicht den Wert NULL hat.

    ' Initialize the ObjectContext.
    schoolContext = New SchoolEntities()
    Dim instructorQuery As ObjectQuery(Of Person) = _
        schoolContext.People.Include("OfficeAssignment") _
        .Where("it.HireDate is not null") _
        .OrderBy("it.LastName")
    instructorGridView.DataSource = instructorQuery _
        .Execute(MergeOption.OverwriteChanges)
    instructorGridView.Columns("EnrollmentDate").Visible = False
    instructorGridView.Columns("EnrollmentDate").Visible = False
    instructorGridView.Columns("OfficeAssignment").Visible = False
    instructorGridView.Columns("StudentGrades").Visible = False
    instructorGridView.Columns("Courses").Visible = False
    
    // Initialize schoolContext.
    schoolContext = new SchoolEntities();
    
    // Define the query to retrieve instructors.
    ObjectQuery<Person> instructorQuery = schoolContext.People
        .Include("OfficeAssignment")
        .Where("it.HireDate is not null")
        .OrderBy("it.LastName");
    
    // Execute and bind the instructorList control to the query.
    instructorGridView.DataSource = instructorQuery.
        Execute(MergeOption.OverwriteChanges);
    instructorGridView.Columns["EnrollmentDate"].Visible = false;
    instructorGridView.Columns["OfficeAssignment"].Visible = false;
    instructorGridView.Columns["StudentGrades"].Visible = false;
    instructorGridView.Columns["Courses"].Visible = false;
    
  5. Kehren Sie zur Entwurfsansicht des InstructorViewer-Formulars zurück, und doppelklicken Sie auf das Button-Steuerelement updateInstructor.

    Der updateInstructor_Click-Ereignishandler wird zur CodeBehind-Datei hinzugefügt.

  6. Fügen Sie dem updateInstructor_Click-Ereignishandler Code hinzu, der alle Änderungen an den Kursleiterinformationen im DataGridView-Steuerelement instructorGridView speichert.

    ' Save object changes to the database, display a 
    ' message, and refresh the form.
    schoolContext.SaveChanges()
    MessageBox.Show("Change(s) saved to the database.")
    Me.Refresh()
    
    // Save object changes to the database, display a 
    // message, and refresh the form.
    schoolContext.SaveChanges();
    MessageBox.Show("Change(s) saved to the database.");
    this.Refresh();
    

Drücken Sie STRG+F5, um die Anwendung auszuführen. Sie können nun Kursleiterinformationen anzeigen und aktualisieren, indem Sie auf View Instructors klicken, in der angezeigten Tabelle die Änderungen vornehmen und dann auf Update Instructor klicken.

Anzeigen und Aktualisieren von Büroinformationen

In diesem Verfahren fügen Sie dem OfficeViewer-Formular Code hinzu, mit dem Bürozuweisungsinformationen angezeigt und aktualisiert werden können. Genauer gesagt erfüllt der Code folgende Aufgaben:

  • Binden der ComboBox an eine Abfrage, die Kursleiterinformationen zurückgibt.

  • Anzeigen von Informationen zum Bürostandort für den ausgewählten Kursleiter in der TextBox.

  • Schreiben von Daten in die Datenbank mithilfe der zuvor zugeordneten gespeicherten Prozeduren, wenn SaveChanges() im updateOffice_Click-Ereignishandler aufgerufen wird.

So zeigen Sie Büroinformationen an und aktualisieren diese

  1. Doppelklicken Sie auf das OfficeViewer-Formular, während das OfficeViewer-Formular im Formular-Designer angezeigt wird.

    Die CodeBehind-Datei für das OfficeViewer-Formular wird geöffnet.

  2. Fügen Sie die folgenden using- (C#) bzw. Imports-Anweisungen (Visual Basic) hinzu:

    Imports System.Data.Objects
    Imports System.Data.Objects.DataClasses
    
    using System.Data.Objects;
    using System.Data.Objects.DataClasses;
    
  3. Fügen Sie eine Eigenschaft zur OfficeViewer-Klasse hinzu, die den Objektkontext darstellt:

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities
    
    // Create an ObjectContext instance based on SchoolEntity.
    private SchoolEntities schoolContext;
    
  4. Fügen Sie dem Formular die folgende Methode hinzu:

    Private Sub ExecuteInstructorQuery()
        ' Define the query to retrieve instructors.
        Dim instructorQuery As ObjectQuery(Of Person) = _
            schoolContext.People.Include("OfficeAssignment"). _
            Where("it.HireDate is not null").OrderBy("it.LastName")
    
        'Execute and bind the instructorList control to the query.
        'Using MergeOption.OverwriteChanges overwrites local data
        'with data from the database.
        instructorList.DataSource = instructorQuery _
            .Execute(MergeOption.OverwriteChanges)
        instructorList.DisplayMember = "LastName"
    End Sub
    
    private void ExecuteInstructorQuery()
    {
        // Define the query to retrieve instructors.
        ObjectQuery<Person> instructorQuery = schoolContext.People
            .Include("OfficeAssignment")
            .Where("it.HireDate is not null")
            .OrderBy("it.LastName");
    
        //Execute and bind the instructorList control to the query.
        //Using MergeOption.OverwriteChanges overwrites local data
        //with data from the database.
        instructorList.DataSource = instructorQuery
            .Execute(MergeOption.OverwriteChanges);
        instructorList.DisplayMember = "LastName";
    }
    

    Diese Methode führt eine Abfrage aus, die Kursleiterinformationen zurückgibt, und bindet die Ergebnisse an das ComboBox-Steuerelement instructorList.

  5. Fügen Sie Code zum OfficeViewer_Load-Ereignishandler zur Initialisierung des Objektkontexts hinzu, und rufen Sie eine Methode auf, die das ComboBox-Steuerelement an eine Abfrage bindet, die alle Person-Typen zurückgibt, deren HireDate nicht den Wert NULL hat.

    schoolContext = New SchoolEntities()
    ExecuteInstructorQuery()
    
    schoolContext = new SchoolEntities();
    ExecuteInstructorQuery();
    
  6. Kehren Sie zur Entwurfsansicht des OfficeViewer-Formulars zurück, und doppelklicken Sie auf das ComboBox-Steuerelement instructorList.

    Der instructorList_SelectedIndexChanged-Ereignishandler wird zur CodeBehind-Datei hinzugefügt.

  7. Fügen Sie dem Ereignishandler Code hinzu, der den Bürostandort des ausgewählten Kursleiters im ListBox-Steuerelement anzeigt und das Button-Steuerelement updateOffice deaktiviert. Dieses Steuerelement wird aktiviert, wenn eine Änderung an einem ausgewählten Bürostandort vorgenommen wurde.

    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;
    
  8. Kehren Sie zur Entwurfsansicht des OfficeViewer-Formulars zurück, und doppelklicken Sie auf das Button-Steuerelement updateOffice.

    Der updateOffice_Click-Ereignishandler wird zur CodeBehind-Datei hinzugefügt.

  9. Fügen Sie Code hinzu, der alle Änderungen an den Büroinformationen im TextBox-Steuerelement officeLocation speichert.

    Try
        Dim currentInstructor As Person = CType(Me.instructorList _
            .SelectedItem(), Person)
        If Me.officeLocation.Text <> String.Empty Then
            If Not currentInstructor.OfficeAssignment Is Nothing Then
                currentInstructor.OfficeAssignment.Location() = _
                    Me.officeLocation.Text
            Else
                Dim temp(8) As Byte
                currentInstructor.OfficeAssignment = _
                    OfficeAssignment.CreateOfficeAssignment( _
                    currentInstructor.PersonID, _
                    Me.officeLocation.Text, temp)
            End If
        Else
            schoolContext.DeleteObject(currentInstructor. _
                                       OfficeAssignment)
        End If
        schoolContext.SaveChanges()
        MessageBox.Show("Change(s) saved to the database.")
    Catch oce As OptimisticConcurrencyException
        MessageBox.Show(oce.Message + " The conflict " & _
                "occurred on " & oce.StateEntries(0).Entity _
                .ToString() & "with key value " & _
                oce.StateEntries(0).EntityKey.EntityKeyValues(0) _
                .Value)
    
        'forceChanges.Enabled = True
    Catch ue As UpdateException
        MessageBox.Show(ue.Message & " Click OK to retrieve " _
                & "the latest data from the database.")
        ExecuteInstructorQuery()
        Me.Refresh()
    Finally
        ' Disable the updateOffice button until another
        ' change has been made to the location.
        updateOffice.Enabled = False
    End Try
    
    try
    {
        Person currentInstructor = (Person)this.instructorList.
            SelectedItem;
        if (this.officeLocation.Text != string.Empty)
        {
            if (currentInstructor.OfficeAssignment != null)
            {
                currentInstructor.OfficeAssignment.Location
                    = this.officeLocation.Text;
            }
            else
            {
                currentInstructor.OfficeAssignment
                    = OfficeAssignment.CreateOfficeAssignment(
                    currentInstructor.PersonID, this.officeLocation.Text,
                    new byte[8]);
            }
        }
        else
        {
            schoolContext.DeleteObject(currentInstructor
                .OfficeAssignment);
        }
        schoolContext.SaveChanges();
        MessageBox.Show("Change(s) saved to the database.");
    }
    catch (OptimisticConcurrencyException oce)
    {
        MessageBox.Show(oce.Message + " The conflict "
            + "occurred on " + oce.StateEntries[0].Entity
            + " with key value " + oce.StateEntries[0].
            EntityKey.EntityKeyValues[0].Value);
    
        //forceChanges.Enabled = true;
    }
    catch (UpdateException ue)
    {
        MessageBox.Show(ue.Message + " Click OK to retrieve "
            + "the latest data from the database.");
        ExecuteInstructorQuery();
        this.Refresh();
    }
    finally
    {
        // Disable the updateOffice button until another
        // change has been made to the location.
        updateOffice.Enabled = false;
    }
    
  10. Kehren Sie zur Entwurfsansicht des OfficeViewer-Formulars zurück, und doppelklicken Sie auf das TextBox-Steuerelement officeLocation.

    Der officeLocation_TextChanged-Ereignishandler wird zur CodeBehind-Datei hinzugefügt.

  11. Fügen Sie Code hinzu, um das Button-Steuerelement updateOffice zu aktivieren, wenn eine Änderung an dem ausgewählten Bürostandort vorgenommen wurde:

    ' 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;
    

Die Anwendung ist jetzt fertig. Drücken Sie STRG+F5, um die Anwendung auszuführen. Sie können jetzt Büroinformationen im Formular OfficeViewer anzeigen und aktualisieren.

Behandlung von Parallelitätskonflikten

In diesem Verfahren fügen Sie dem Office Viewer-Formular Code hinzu, der Clientänderungen an der Datenbank nach einem Parallelitätskonflikt erzwingt.

So behandeln Sie Parallelitätskonflikte

  1. Doppelklicken Sie im Projektmappen-Explorer auf InstructorViewer.vb oder InstructorViewer.cs.

    Das Formular wird im Formular-Designer geöffnet.

  2. Doppelklicken Sie auf die Schaltfläche View Offices.

    Die CodeBehind-Datei für das Formular InstructorViewer wird geöffnet.

  3. Fügen Sie dem viewOffices_Click-Ereignishandler folgenden Code hinzu, sodass zwei OfficeViewer-Formulare geladen werden, wenn auf die Schaltfläche View Offices geklickt wird.

    Dim officeViewer2 As New OfficeViewer()
    officeViewer2.Text = "Demonstrate Conflict"
    officeViewer2.Visible = True
    
    OfficeViewer officeViewer2 = new OfficeViewer();
    officeViewer2.Text = "Demonstrate Conflict";
    officeViewer2.Visible = true;
    
  4. Doppelklicken Sie im Projektmappen-Explorer auf OfficeViewer.vb oder OfficeViewer.cs.

    Das Formular wird im Formular-Designer geöffnet.

  5. Ziehen Sie ein Button-Steuerelement von der Toolbox auf das Formular. Legen Sie für den Namen forceChanges und für den Text Force Changes fest.

  6. Doppelklicken Sie auf die Schaltfläche Force Changes.

    Die CodeBehind-Datei für das Formular Office Viewer wird geöffnet.

  7. Fügen Sie dem forceChanges_Click-Ereignishandler folgenden Code hinzu, sodass Änderungen auf dem Client auf dem Server erzwungen werden oder an das ComboBox-Steuerelement instructorList gebundene Daten aus der Datenbank aktualisiert werden.

    Dim currentInstructor As Person = CType(Me.instructorList _
        .SelectedItem(), Person)
    Try
        currentInstructor.OfficeAssignment.Location = _
            Me.officeLocation.Text
        ' Using RefreshMode.ClientWins disables the
        ' optimistic concurrency check.
        schoolContext.Refresh(RefreshMode.ClientWins, _
                    currentInstructor.OfficeAssignment)
        schoolContext.SaveChanges()
        MessageBox.Show("Change(s) saved to the database.")
    
        'forceChanges.Enabled = False
    Catch ioe As InvalidOperationException
        MessageBox.Show(ioe.Message + " Click OK to retrieve " _
                + "the latest data from the database.")
        ExecuteInstructorQuery()
        Me.Refresh()
    End Try
    
    Person currentInstructor = (Person)this.instructorList
        .SelectedItem;
    try
    {
        currentInstructor.OfficeAssignment.Location
                    = this.officeLocation.Text;
    
        // Using RefreshMode.ClientWins disables the
        // optimistic concurrency check.
        schoolContext.Refresh(RefreshMode.ClientWins,
                currentInstructor.OfficeAssignment);
        schoolContext.SaveChanges();
        MessageBox.Show("Change(s) saved to the database.");
    
        //forceChanges.Enabled = false;
    }
    catch (InvalidOperationException ioe)
    {
        MessageBox.Show(ioe.Message + " Click OK to retrieve "
            + "the latest data from the database.");
        ExecuteInstructorQuery();
        this.Refresh();
    }
    
  8. Entfernen Sie im instructorList_SelectedIndexChanged-Ereignishandler das Kommentarzeichen vor der Codezeile forceChanges = False (Visual Basic) bzw. forceChanges = false; (C#), sodass die Schaltfläche Force Changes deaktiviert wird, wenn ein neuer Kursleiter ausgewählt wird.

  9. Entfernen Sie im updateOffice_Click-Ereignishandler das Kommentarzeichen vor der Codezeile forceChanges = True (Visual Basic) bzw. forceChanges = true; (C#), sodass die Schaltfläche Force Changes aktiviert wird, wenn ein Parallelitätskonflikt auftritt.

  10. Entfernen Sie im forceChanges_Click-Ereignishandler das Kommentarzeichen vor der Codezeile forceChanges = False (Visual Basic) bzw. forceChanges = false; (C#), sodass die Schaltfläche Force Changes deaktiviert wird, nachdem Änderungen in der Datenbank erzwungen wurden.

Führen Sie die Anwendung aus (drücken Sie STRG+F5), klicken Sie auf View Instructors und dann auf View Offices, um die Behandlung eines Parallelitätskonflikts durch die Anwendung anzuzeigen. Aktualisieren Sie einen Bürostandort im Formular Office Viewer, und versuchen Sie anschließend, denselben Bürostandort im anderen Formular Demonstrate Conflict zu aktualisieren. Ein Meldungsfeld wird angezeigt, das Sie über den Parallelitätskonflikt informiert. Um die Änderungen aus dem Formular Demonstrate Conflict in der Datenbank zu erzwingen, klicken Sie auf Force Changes.

Codelisting

Dieser Abschnitt enthält abschließende Versionen der CodeBehind-Dateien für die Formulare InstructorViewer und OfficeViewer.

Imports System.Data.Objects
Imports System.Data.Objects.DataClasses
Public Class InstructorViewer

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities

    Private Sub viewOffices_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles viewOffices.Click
        Dim officeViewer As New OfficeViewer()
        officeViewer.Visible = True

        Dim officeViewer2 As New OfficeViewer()
        officeViewer2.Text = "Demonstrate Conflict"
        officeViewer2.Visible = True
    End Sub

    Private Sub InstructorViewer_Load(ByVal sender As System.Object, _
                    ByVal e As System.EventArgs) Handles MyBase.Load
        ' Initialize the ObjectContext.
        schoolContext = New SchoolEntities()
        Dim instructorQuery As ObjectQuery(Of Person) = _
            schoolContext.People.Include("OfficeAssignment") _
            .Where("it.HireDate is not null") _
            .OrderBy("it.LastName")
        instructorGridView.DataSource = instructorQuery _
            .Execute(MergeOption.OverwriteChanges)
        instructorGridView.Columns("EnrollmentDate").Visible = False
        instructorGridView.Columns("EnrollmentDate").Visible = False
        instructorGridView.Columns("OfficeAssignment").Visible = False
        instructorGridView.Columns("StudentGrades").Visible = False
        instructorGridView.Columns("Courses").Visible = False
    End Sub

    Private Sub updateInstructor_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles updateInstructor.Click
        ' Save object changes to the database, display a 
        ' message, and refresh the form.
        schoolContext.SaveChanges()
        MessageBox.Show("Change(s) saved to the database.")
        Me.Refresh()
    End Sub
End Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Objects;
using System.Data.Objects.DataClasses;

namespace CourseManager
{
    public partial class InstructorViewer : Form
    {
        // Create an ObjectContext instance based on SchoolEntity.
        private SchoolEntities schoolContext;

        public InstructorViewer()
        {
            InitializeComponent();
        }

        private void viewOffices_Click(object sender, EventArgs e)
        {
            OfficeViewer officeViewer = new OfficeViewer();
            officeViewer.Visible = true;

            OfficeViewer officeViewer2 = new OfficeViewer();
            officeViewer2.Text = "Demonstrate Conflict";
            officeViewer2.Visible = true;
        }

        private void InstructorViewer_Load(object sender, EventArgs e)
        {
            // Initialize schoolContext.
            schoolContext = new SchoolEntities();

            // Define the query to retrieve instructors.
            ObjectQuery<Person> instructorQuery = schoolContext.People
                .Include("OfficeAssignment")
                .Where("it.HireDate is not null")
                .OrderBy("it.LastName");

            // Execute and bind the instructorList control to the query.
            instructorGridView.DataSource = instructorQuery.
                Execute(MergeOption.OverwriteChanges);
            instructorGridView.Columns["EnrollmentDate"].Visible = false;
            instructorGridView.Columns["OfficeAssignment"].Visible = false;
            instructorGridView.Columns["StudentGrades"].Visible = false;
            instructorGridView.Columns["Courses"].Visible = false;
        }

        private void updateInstructor_Click(object sender, EventArgs e)
        {
            // Save object changes to the database, display a 
            // message, and refresh the form.
            schoolContext.SaveChanges();
            MessageBox.Show("Change(s) saved to the database.");
            this.Refresh();
        }
    }
}
Imports System.Data.Objects
Imports System.Data.Objects.DataClasses
Public Class OfficeViewer

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities

    Private Sub OfficeViewer_Load(ByVal sender As System.Object, _
                ByVal e As System.EventArgs) Handles MyBase.Load
        schoolContext = New SchoolEntities()
        ExecuteInstructorQuery()
    End Sub

    Private Sub instructorList_SelectedIndexChanged(ByVal sender As  _
                System.Object, ByVal e As System.EventArgs) Handles _
                instructorList.SelectedIndexChanged
        Dim instructor As Person = CType(Me.instructorList _
         .SelectedItem(), Person)

        If Not instructor.OfficeAssignment Is Nothing Then
            Me.officeLocation.Text = instructor _
             .OfficeAssignment.Location.ToString()
        Else
            Me.officeLocation.Text = ""
        End If

        ' Disable the updateOffice button until a change
        ' has been made to the office location.
        updateOffice.Enabled = False

        'forceChanges.Enabled = False
    End Sub

    Private Sub updateOffice_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles updateOffice.Click
        Try
            Dim currentInstructor As Person = CType(Me.instructorList _
                .SelectedItem(), Person)
            If Me.officeLocation.Text <> String.Empty Then
                If Not currentInstructor.OfficeAssignment Is Nothing Then
                    currentInstructor.OfficeAssignment.Location() = _
                        Me.officeLocation.Text
                Else
                    Dim temp(8) As Byte
                    currentInstructor.OfficeAssignment = _
                        OfficeAssignment.CreateOfficeAssignment( _
                        currentInstructor.PersonID, _
                        Me.officeLocation.Text, temp)
                End If
            Else
                schoolContext.DeleteObject(currentInstructor. _
                                           OfficeAssignment)
            End If
            schoolContext.SaveChanges()
            MessageBox.Show("Change(s) saved to the database.")
        Catch oce As OptimisticConcurrencyException
            MessageBox.Show(oce.Message + " The conflict " & _
                    "occurred on " & oce.StateEntries(0).Entity _
                    .ToString() & "with key value " & _
                    oce.StateEntries(0).EntityKey.EntityKeyValues(0) _
                    .Value)

            'forceChanges.Enabled = True
        Catch ue As UpdateException
            MessageBox.Show(ue.Message & " Click OK to retrieve " _
                    & "the latest data from the database.")
            ExecuteInstructorQuery()
            Me.Refresh()
        Finally
            ' Disable the updateOffice button until another
            ' change has been made to the location.
            updateOffice.Enabled = False
        End Try
    End Sub

    Private Sub officeLocation_TextChanged(ByVal sender As  _
                System.Object, ByVal e As System.EventArgs) _
                Handles officeLocation.TextChanged
        ' Enable the udateOffice button when there is a change
        ' to write to the database.
        updateOffice.Enabled = True
    End Sub

    Private Sub forceChanges_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles forceChanges.Click
        Dim currentInstructor As Person = CType(Me.instructorList _
            .SelectedItem(), Person)
        Try
            currentInstructor.OfficeAssignment.Location = _
                Me.officeLocation.Text
            ' Using RefreshMode.ClientWins disables the
            ' optimistic concurrency check.
            schoolContext.Refresh(RefreshMode.ClientWins, _
                        currentInstructor.OfficeAssignment)
            schoolContext.SaveChanges()
            MessageBox.Show("Change(s) saved to the database.")

            'forceChanges.Enabled = False
        Catch ioe As InvalidOperationException
            MessageBox.Show(ioe.Message + " Click OK to retrieve " _
                    + "the latest data from the database.")
            ExecuteInstructorQuery()
            Me.Refresh()
        End Try
    End Sub

    Private Sub ExecuteInstructorQuery()
        ' Define the query to retrieve instructors.
        Dim instructorQuery As ObjectQuery(Of Person) = _
            schoolContext.People.Include("OfficeAssignment"). _
            Where("it.HireDate is not null").OrderBy("it.LastName")

        'Execute and bind the instructorList control to the query.
        'Using MergeOption.OverwriteChanges overwrites local data
        'with data from the database.
        instructorList.DataSource = instructorQuery _
            .Execute(MergeOption.OverwriteChanges)
        instructorList.DisplayMember = "LastName"
    End Sub
End Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Objects;
using System.Data.Objects.DataClasses;

namespace CourseManager
{
    public partial class OfficeViewer : Form
    {
        // Create an ObjectContext instance based on SchoolEntity.
        private SchoolEntities schoolContext;

        public OfficeViewer()
        {
            InitializeComponent();
        }

        private void OfficeViewer_Load(object sender, EventArgs e)
        {
            schoolContext = new SchoolEntities();
            ExecuteInstructorQuery();
        }

        private void instructorList_SelectedIndexChanged(object sender,
        EventArgs e)
        {
            Person instructor = (Person)this.instructorList.
                SelectedItem;

            if (instructor.OfficeAssignment != null)
            {
                this.officeLocation.Text = instructor.
                    OfficeAssignment.Location.ToString();
            }
            else
            {
                this.officeLocation.Text = "";
            }

            // Disable the updateOffice button until a change
            // has been made to the office location.
            updateOffice.Enabled = false;

            //forceChanges.Enabled = false;
        }

        private void updateOffice_Click(object sender, EventArgs e)
        {
            try
            {
                Person currentInstructor = (Person)this.instructorList.
                    SelectedItem;
                if (this.officeLocation.Text != string.Empty)
                {
                    if (currentInstructor.OfficeAssignment != null)
                    {
                        currentInstructor.OfficeAssignment.Location
                            = this.officeLocation.Text;
                    }
                    else
                    {
                        currentInstructor.OfficeAssignment
                            = OfficeAssignment.CreateOfficeAssignment(
                            currentInstructor.PersonID, this.officeLocation.Text,
                            new byte[8]);
                    }
                }
                else
                {
                    schoolContext.DeleteObject(currentInstructor
                        .OfficeAssignment);
                }
                schoolContext.SaveChanges();
                MessageBox.Show("Change(s) saved to the database.");
            }
            catch (OptimisticConcurrencyException oce)
            {
                MessageBox.Show(oce.Message + " The conflict "
                    + "occurred on " + oce.StateEntries[0].Entity
                    + " with key value " + oce.StateEntries[0].
                    EntityKey.EntityKeyValues[0].Value);

                //forceChanges.Enabled = true;
            }
            catch (UpdateException ue)
            {
                MessageBox.Show(ue.Message + " Click OK to retrieve "
                    + "the latest data from the database.");
                ExecuteInstructorQuery();
                this.Refresh();
            }
            finally
            {
                // Disable the updateOffice button until another
                // change has been made to the location.
                updateOffice.Enabled = false;
            }
        }

        private void officeLocation_TextChanged(object sender, EventArgs e)
        {
            // Enable the udateOffice button when there is a change
            // to write to the database.
            updateOffice.Enabled = true;
        }

        private void forceChanges_Click(object sender, EventArgs e)
        {
            Person currentInstructor = (Person)this.instructorList
                .SelectedItem;
            try
            {
                currentInstructor.OfficeAssignment.Location
                            = this.officeLocation.Text;

                // Using RefreshMode.ClientWins disables the
                // optimistic concurrency check.
                schoolContext.Refresh(RefreshMode.ClientWins,
                        currentInstructor.OfficeAssignment);
                schoolContext.SaveChanges();
                MessageBox.Show("Change(s) saved to the database.");

                //forceChanges.Enabled = false;
            }
            catch (InvalidOperationException ioe)
            {
                MessageBox.Show(ioe.Message + " Click OK to retrieve "
                    + "the latest data from the database.");
                ExecuteInstructorQuery();
                this.Refresh();
            }
        }

        private void ExecuteInstructorQuery()
        {
            // Define the query to retrieve instructors.
            ObjectQuery<Person> instructorQuery = schoolContext.People
                .Include("OfficeAssignment")
                .Where("it.HireDate is not null")
                .OrderBy("it.LastName");

            //Execute and bind the instructorList control to the query.
            //Using MergeOption.OverwriteChanges overwrites local data
            //with data from the database.
            instructorList.DataSource = instructorQuery
                .Execute(MergeOption.OverwriteChanges);
            instructorList.DisplayMember = "LastName";
        }
    }
}

Nächste Schritte

Sie haben die Einfüge-, Aktualisierungs- und Löschvorgänge einer Entität erfolgreich gespeicherten Prozeduren zugeordnet. Weitere Informationen zum Erstellen von Anwendungen, die Entity Framework verwenden, finden Sie unter Entity Framework.

Siehe auch

Weitere Ressourcen

Szenarien für die Verwendung der Entity Data Model-Tools
Aufgaben der Entity Data Model-Tools