Exemplarische Vorgehensweise: Zuordnen einer Entität zu gespeicherten Prozeduren
In diesem Thema wird gezeigt, wie gespeicherten Prozeduren mit dem ADO.NET Entity Data Model-Designer (Entity Designer) die Einfüge-, Aktualisierungs- und Löschvorgänge eines Entitätstyps 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 gespeicherten Prozeduren zu, indem Sie das in der Anwendung CourseManager (weitere Informationen finden Sie weiter unten in diesem Thema im Abschnitt "Erforderliche Komponenten") verwendete Entity Data Model (EDM) ändern. Außerdem schreiben Sie Code, mit dem Entitätstypen eingefügt, aktualisiert und gelöscht werden.
Erforderliche Komponenten
Um diese exemplarische Vorgehensweise durchzuführen, müssen Sie die Anwendung "CourseManager" erstellen. Weitere Informationen und Anweisungen finden Sie im Entity Framework-Schnellstart. Nachdem Sie diese Anwendung erstellt haben, ändern Sie das zugehörige EDM, indem Sie zwei Entitätstypen gespeicherten Prozeduren zuordnen.
Hinweis |
---|
Da viele der exemplarischen Vorgehensweisen in dieser Dokumentation die Anwendung "CourseManager" als Ausgangspunkt verwenden, wird empfohlen, für diese exemplarische Vorgehensweise eine Kopie der Anwendung "CourseManager" zu verwenden, statt den ursprünglichen Code von CourseManager 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.
So ordnen Sie die "Person"-Entität gespeicherten Prozeduren zu
Öffnen Sie in Visual Studio die Projektmappe "CourseManager".
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.
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.
Klicken Sie auf <Insert Function auswählen>.
Das Feld wird zu einer Dropdownliste mit den im EDM enthaltenen gespeicherten Prozeduren.
Wählen Sie in der Dropdownliste den Eintrag InsertPerson aus.
Es werden Standardmappings zwischen Parametern gespeicherter Prozeduren und Entitätseigenschaften angezeigt. Pfeile geben die Mappingrichtung an: Eigenschaftenwerte sind Parametern gespeicherter Prozeduren zugeordnet.
Klicken Sie auf <Result Binding hinzufügen>.
Das Feld wird bearbeitbar.
Ersetzen Sie <Result Binding hinzufügen> durch NewPersonID, den Namen des Parameters, der von der gespeicherten Prozedur InsertPerson zurückgegeben wird. 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.
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.
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
Wenn der Entitätstyp an einem Ende eines 1:1-Mappings gespeicherten Prozeduren zugeordnet ist, muss die Entität am anderen Ende des Mappings ebenfalls gespeicherten Prozeduren zugeordnet sein. In diesem Beispiel wird der OfficeAssignment-Entitätstyp gespeicherten Prozeduren zugeordnet, da er über ein 1:1-Mapping mit dem Person-Entitätstyp verfügt. Bei diesem Mapping 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
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.
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.
Klicken Sie auf <Result Binding hinzufügen>.
Das Feld wird bearbeitbar.
Geben Sie Timestamp anstelle von <Result Binding hinzufügen> ein.
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.
Wählen Sie in der Dropdownliste den Eintrag Timestamp aus.
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.
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.
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.
Klicken Sie auf <Result Binding hinzufügen>.
Das Feld wird bearbeitbar.
Ersetzen Sie <Result Binding hinzufügen> durch Timestamp.
Klicken Sie auf das leere Feld in der Propery/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.
Wählen Sie in der Dropdownliste den Eintrag Timestamp aus.
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
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.
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.
Ziehen Sie ein DataGridView-Steuerelement von der Toolbox auf das Formular, und legen Sie den Namen im Fenster Eigenschaften auf instructorGridView fest.
Ziehen Sie ein Button-Steuerelement von der Toolbox auf das Formular. Legen Sie für den NamenupdateInstructor und für den TextUpdate Instructor fest.
Ziehen Sie ein weiteres Button-Steuerelement von der Toolbox auf das Formular. Legen Sie für den NamenviewOffices und für den TextView Offices fest.
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.
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.
Ziehen Sie ein ComboBox-Steuerelement von der Toolbox auf das Formular, und legen Sie seinen Namen auf instructorList fest.
Ziehen Sie ein TextBox-Steuerelement von der Toolbox auf das Formular, und legen Sie seinen Namen auf officeLocation fest.
Ziehen Sie ein Button-Steuerelement von der Toolbox auf das Formular. Legen Sie für den NamenupdateOffice und für den TextUpdate Office fest.
Doppelklicken Sie im Projektmappen-Explorer auf CourseViewer.vb oder CourseViewer.cs.
Die Entwurfsansicht des CourseViewer-Formulars wird angezeigt.
Ziehen Sie ein Button-Steuerelement von der Toolbox auf das Formular.
Legen Sie im Fenster Eigenschaften die Name-Eigenschaft des Button auf viewInstructors und die Text-Eigenschaft auf View Instructors fest.
Doppelklicken Sie auf das Button-Steuerelement viewInstructors.
Die CodeBehind-Datei für das CourseViewer-Formular wird geöffnet.
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;
Kehren Sie zur Entwurfsansicht des InstructorViewer-Formulars zurück.
Doppelklicken Sie auf das Button-Steuerelement viewOffices.
Die CodeBehind-Datei für Form2 wird geöffnet.
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 Binden von Objekten an Steuerelemente (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
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.
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;
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;
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.Person.Include("OfficeAssignment") _ .Where("it.HireDate is not null") _ .OrderBy("it.LastName") instructorGridView.DataSource = instructorQuery _ .Execute(MergeOption.OverwriteChanges) instructorGridView.Columns("EnrollmentDate").Visible = False
// Initialize schoolContext. schoolContext = new SchoolEntities(); // Define the query to retrieve instructors. ObjectQuery<Person> instructorQuery = schoolContext.Person .Include("OfficeAssignment") .Where("it.HireDate is not null") .OrderBy("it.LastName"); // Execute and bind the instructorList control to the query. instructorGridView.DataSource = instructorQuery. Execute(MergeOption.OverwriteChanges); instructorGridView.Columns["EnrollmentDate"].Visible = false;
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.
Fügen Sie dem updateInstructor_Click-Ereignishandler Code hinzu, der alle Änderungen an den Kursleiterinformationen im DataGridView-Steuerelement instructorGridView speichert.
Dim numChanges As Integer ' Save object changes to the database, display a ' message, and refresh the form. numChanges = schoolContext.SaveChanges() MessageBox.Show(numChanges.ToString() + _ " change(s) saved to the database.") Me.Refresh()
int numChanges; // Save object changes to the database, display a // message, and refresh the form. numChanges = schoolContext.SaveChanges(); MessageBox.Show(numChanges.ToString() + " change(s) saved to the database."); this.Refresh();
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
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.
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;
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;
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.Person.Include("OfficeAssignment"). _ Where("it.HireDate is not null").OrderBy("it.LastName") 'Execute and bind the instructorList control to the query. 'Using MergeOption.OverwriteChanges overwrites local data 'with data from the database. instructorList.DataSource = instructorQuery _ .Execute(MergeOption.OverwriteChanges) instructorList.DisplayMember = "LastName" End Sub
private void ExecuteInstructorQuery() { // Define the query to retrieve instructors. ObjectQuery<Person> instructorQuery = schoolContext.Person .Include("OfficeAssignment") .Where("it.HireDate is not null") .OrderBy("it.LastName"); //Execute and bind the instructorList control to the query. //Using MergeOption.OverwriteChanges overwrites local data //with data from the database. instructorList.DataSource = instructorQuery .Execute(MergeOption.OverwriteChanges); instructorList.DisplayMember = "LastName"; }
Diese Methode führt eine Abfrage aus, die Kursleiterinformationen zurückgibt, und bindet die Ergebnisse an das ComboBox-Steuerelement instructorList.
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();
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.
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;
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.
Fügen Sie Code hinzu, der alle Änderungen an den Büroinformationen im TextBox-Steuerelement officeLocation speichert.
Try Dim numChanges As Integer Dim currentInstructor As Person = CType(Me.instructorList _ .SelectedItem(), Person) If Me.officeLocation.Text <> String.Empty Then If Not currentInstructor.OfficeAssignment Is Nothing Then currentInstructor.OfficeAssignment.Location() = _ Me.officeLocation.Text Else Dim temp(8) As Byte currentInstructor.OfficeAssignment = _ OfficeAssignment.CreateOfficeAssignment( _ currentInstructor.PersonID, _ Me.officeLocation.Text, temp) End If Else schoolContext.DeleteObject(currentInstructor. _ OfficeAssignment) End If numChanges = schoolContext.SaveChanges() MessageBox.Show(numChanges.ToString() _ + " change(s) saved to the database.") Catch oce As OptimisticConcurrencyException MessageBox.Show(oce.Message + " The conflict " & _ "occurred on " & oce.StateEntries(0).Entity _ .ToString() & "with key value " & _ oce.StateEntries(0).EntityKey.EntityKeyValues(0) _ .Value) 'forceChanges.Enabled = True Catch ue As UpdateException MessageBox.Show(ue.Message & " Click OK to retrieve " _ & "the latest data from the database.") ExecuteInstructorQuery() Me.Refresh() Finally ' Disable the updateOffice button until another ' change has been made to the location. updateOffice.Enabled = False End Try
try { int numChanges; Person currentInstructor = (Person)this.instructorList. SelectedItem; if (this.officeLocation.Text != string.Empty) { if (currentInstructor.OfficeAssignment != null) { currentInstructor.OfficeAssignment.Location = this.officeLocation.Text; } else { currentInstructor.OfficeAssignment = OfficeAssignment.CreateOfficeAssignment( currentInstructor.PersonID, this.officeLocation.Text, new byte[8]); } } else { schoolContext.DeleteObject(currentInstructor .OfficeAssignment); } numChanges = schoolContext.SaveChanges(); MessageBox.Show(numChanges.ToString() + " change(s) saved to the database."); } catch (OptimisticConcurrencyException oce) { MessageBox.Show(oce.Message + " The conflict " + "occurred on " + oce.StateEntries[0].Entity + " with key value " + oce.StateEntries[0]. EntityKey.EntityKeyValues[0].Value); //forceChanges.Enabled = true; } catch (UpdateException ue) { MessageBox.Show(ue.Message + " Click OK to retrieve " + "the latest data from the database."); ExecuteInstructorQuery(); this.Refresh(); } finally { // Disable the updateOffice button until another // change has been made to the location. updateOffice.Enabled = false; }
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.
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
Doppelklicken Sie im Projektmappen-Explorer auf InstructorViewer.vb oder InstructorViewer.cs.
Das Formular wird im Formular-Designer geöffnet.
Doppelklicken Sie auf die Schaltfläche View Offices.
Die CodeBehind-Datei für das Formular InstructorViewer wird geöffnet.
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;
Doppelklicken Sie im Projektmappen-Explorer auf OfficeViewer.vb oder OfficeViewer.cs.
Das Formular wird im Formular-Designer geöffnet.
Ziehen Sie ein Button-Steuerelement von der Toolbox auf das Formular. Legen Sie für den NamenforceChanges und für den TextForce Changes fest.
Doppelklicken Sie auf die Schaltfläche Force Changes.
Die CodeBehind-Datei für das Formular Office Viewer wird geöffnet.
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 numChanges As Integer Dim currentInstructor As Person = CType(Me.instructorList _ .SelectedItem(), Person) Try currentInstructor.OfficeAssignment.Location = _ Me.officeLocation.Text ' Using RefreshMode.ClientWins disables the ' optimistic concurrency check. schoolContext.Refresh(RefreshMode.ClientWins, _ currentInstructor.OfficeAssignment) numChanges = schoolContext.SaveChanges() MessageBox.Show(numChanges.ToString() + _ " change(s) saved to the database.") 'forceChanges.Enabled = False Catch ioe As InvalidOperationException MessageBox.Show(ioe.Message + " Click OK to retrieve " _ + "the latest data from the database.") ExecuteInstructorQuery() Me.Refresh() End Try
int numChanges; Person currentInstructor = (Person)this.instructorList .SelectedItem; try { currentInstructor.OfficeAssignment.Location = this.officeLocation.Text; // Using RefreshMode.ClientWins disables the // optimistic concurrency check. schoolContext.Refresh(RefreshMode.ClientWins, currentInstructor.OfficeAssignment); numChanges = schoolContext.SaveChanges(); MessageBox.Show(numChanges.ToString() + " change(s) saved to the database."); //forceChanges.Enabled = false; } catch (InvalidOperationException ioe) { MessageBox.Show(ioe.Message + " Click OK to retrieve " + "the latest data from the database."); ExecuteInstructorQuery(); this.Refresh(); }
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.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.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.Person.Include("OfficeAssignment") _
.Where("it.HireDate is not null") _
.OrderBy("it.LastName")
instructorGridView.DataSource = instructorQuery _
.Execute(MergeOption.OverwriteChanges)
instructorGridView.Columns("EnrollmentDate").Visible = False
End Sub
Private Sub updateInstructor_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles updateInstructor.Click
Dim numChanges As Integer
' Save object changes to the database, display a
' message, and refresh the form.
numChanges = schoolContext.SaveChanges()
MessageBox.Show(numChanges.ToString() + _
" change(s) saved to the database.")
Me.Refresh()
End Sub
End Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
namespace CourseManager
{
public partial class InstructorViewer : Form
{
// Create an ObjectContext instance based on SchoolEntity.
private SchoolEntities schoolContext;
public InstructorViewer()
{
InitializeComponent();
}
private void viewOffices_Click(object sender, EventArgs e)
{
OfficeViewer officeViewer = new OfficeViewer();
officeViewer.Visible = true;
OfficeViewer officeViewer2 = new OfficeViewer();
officeViewer2.Text = "Demonstrate Conflict";
officeViewer2.Visible = true;
}
private void InstructorViewer_Load(object sender, EventArgs e)
{
// Initialize schoolContext.
schoolContext = new SchoolEntities();
// Define the query to retrieve instructors.
ObjectQuery<Person> instructorQuery = schoolContext.Person
.Include("OfficeAssignment")
.Where("it.HireDate is not null")
.OrderBy("it.LastName");
// Execute and bind the instructorList control to the query.
instructorGridView.DataSource = instructorQuery.
Execute(MergeOption.OverwriteChanges);
instructorGridView.Columns["EnrollmentDate"].Visible = false;
}
private void updateInstructor_Click(object sender, EventArgs e)
{
int numChanges;
// Save object changes to the database, display a
// message, and refresh the form.
numChanges = schoolContext.SaveChanges();
MessageBox.Show(numChanges.ToString() +
" change(s) saved to the database.");
this.Refresh();
}
}
}
Imports System.Data.Objects
Imports System.Data.Objects.DataClasses
Public Class OfficeViewer
' Create an ObjectContext instance based on SchoolEntity.
Private schoolContext As SchoolEntities
Private Sub OfficeViewer_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
schoolContext = New SchoolEntities()
ExecuteInstructorQuery()
End Sub
Private Sub instructorList_SelectedIndexChanged(ByVal sender As _
System.Object, ByVal e As System.EventArgs) Handles _
instructorList.SelectedIndexChanged
Dim instructor As Person = CType(Me.instructorList _
.SelectedItem(), Person)
If Not instructor.OfficeAssignment Is Nothing Then
Me.officeLocation.Text = instructor _
.OfficeAssignment.Location.ToString()
Else
Me.officeLocation.Text = ""
End If
' Disable the updateOffice button until a change
' has been made to the office location.
updateOffice.Enabled = False
'forceChanges.Enabled = False
End Sub
Private Sub updateOffice_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles updateOffice.Click
Try
Dim numChanges As Integer
Dim currentInstructor As Person = CType(Me.instructorList _
.SelectedItem(), Person)
If Me.officeLocation.Text <> String.Empty Then
If Not currentInstructor.OfficeAssignment Is Nothing Then
currentInstructor.OfficeAssignment.Location() = _
Me.officeLocation.Text
Else
Dim temp(8) As Byte
currentInstructor.OfficeAssignment = _
OfficeAssignment.CreateOfficeAssignment( _
currentInstructor.PersonID, _
Me.officeLocation.Text, temp)
End If
Else
schoolContext.DeleteObject(currentInstructor. _
OfficeAssignment)
End If
numChanges = schoolContext.SaveChanges()
MessageBox.Show(numChanges.ToString() _
+ " change(s) saved to the database.")
Catch oce As OptimisticConcurrencyException
MessageBox.Show(oce.Message + " The conflict " & _
"occurred on " & oce.StateEntries(0).Entity _
.ToString() & "with key value " & _
oce.StateEntries(0).EntityKey.EntityKeyValues(0) _
.Value)
'forceChanges.Enabled = True
Catch ue As UpdateException
MessageBox.Show(ue.Message & " Click OK to retrieve " _
& "the latest data from the database.")
ExecuteInstructorQuery()
Me.Refresh()
Finally
' Disable the updateOffice button until another
' change has been made to the location.
updateOffice.Enabled = False
End Try
End Sub
Private Sub officeLocation_TextChanged(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles officeLocation.TextChanged
' Enable the udateOffice button when there is a change
' to write to the database.
updateOffice.Enabled = True
End Sub
Private Sub forceChanges_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles forceChanges.Click
Dim numChanges As Integer
Dim currentInstructor As Person = CType(Me.instructorList _
.SelectedItem(), Person)
Try
currentInstructor.OfficeAssignment.Location = _
Me.officeLocation.Text
' Using RefreshMode.ClientWins disables the
' optimistic concurrency check.
schoolContext.Refresh(RefreshMode.ClientWins, _
currentInstructor.OfficeAssignment)
numChanges = schoolContext.SaveChanges()
MessageBox.Show(numChanges.ToString() + _
" change(s) saved to the database.")
'forceChanges.Enabled = False
Catch ioe As InvalidOperationException
MessageBox.Show(ioe.Message + " Click OK to retrieve " _
+ "the latest data from the database.")
ExecuteInstructorQuery()
Me.Refresh()
End Try
End Sub
Private Sub ExecuteInstructorQuery()
' Define the query to retrieve instructors.
Dim instructorQuery As ObjectQuery(Of Person) = _
schoolContext.Person.Include("OfficeAssignment"). _
Where("it.HireDate is not null").OrderBy("it.LastName")
'Execute and bind the instructorList control to the query.
'Using MergeOption.OverwriteChanges overwrites local data
'with data from the database.
instructorList.DataSource = instructorQuery _
.Execute(MergeOption.OverwriteChanges)
instructorList.DisplayMember = "LastName"
End Sub
End Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
namespace CourseManager
{
public partial class OfficeViewer : Form
{
// Create an ObjectContext instance based on SchoolEntity.
private SchoolEntities schoolContext;
public OfficeViewer()
{
InitializeComponent();
}
private void OfficeViewer_Load(object sender, EventArgs e)
{
schoolContext = new SchoolEntities();
ExecuteInstructorQuery();
}
private void instructorList_SelectedIndexChanged(object sender,
EventArgs e)
{
Person instructor = (Person)this.instructorList.
SelectedItem;
if (instructor.OfficeAssignment != null)
{
this.officeLocation.Text = instructor.
OfficeAssignment.Location.ToString();
}
else
{
this.officeLocation.Text = "";
}
// Disable the updateOffice button until a change
// has been made to the office location.
updateOffice.Enabled = false;
//forceChanges.Enabled = false;
}
private void updateOffice_Click(object sender, EventArgs e)
{
try
{
int numChanges;
Person currentInstructor = (Person)this.instructorList.
SelectedItem;
if (this.officeLocation.Text != string.Empty)
{
if (currentInstructor.OfficeAssignment != null)
{
currentInstructor.OfficeAssignment.Location
= this.officeLocation.Text;
}
else
{
currentInstructor.OfficeAssignment
= OfficeAssignment.CreateOfficeAssignment(
currentInstructor.PersonID, this.officeLocation.Text,
new byte[8]);
}
}
else
{
schoolContext.DeleteObject(currentInstructor
.OfficeAssignment);
}
numChanges = schoolContext.SaveChanges();
MessageBox.Show(numChanges.ToString() +
" change(s) saved to the database.");
}
catch (OptimisticConcurrencyException oce)
{
MessageBox.Show(oce.Message + " The conflict "
+ "occurred on " + oce.StateEntries[0].Entity
+ " with key value " + oce.StateEntries[0].
EntityKey.EntityKeyValues[0].Value);
//forceChanges.Enabled = true;
}
catch (UpdateException ue)
{
MessageBox.Show(ue.Message + " Click OK to retrieve "
+ "the latest data from the database.");
ExecuteInstructorQuery();
this.Refresh();
}
finally
{
// Disable the updateOffice button until another
// change has been made to the location.
updateOffice.Enabled = false;
}
}
private void officeLocation_TextChanged(object sender, EventArgs e)
{
// Enable the udateOffice button when there is a change
// to write to the database.
updateOffice.Enabled = true;
}
private void forceChanges_Click(object sender, EventArgs e)
{
int numChanges;
Person currentInstructor = (Person)this.instructorList
.SelectedItem;
try
{
currentInstructor.OfficeAssignment.Location
= this.officeLocation.Text;
// Using RefreshMode.ClientWins disables the
// optimistic concurrency check.
schoolContext.Refresh(RefreshMode.ClientWins,
currentInstructor.OfficeAssignment);
numChanges = schoolContext.SaveChanges();
MessageBox.Show(numChanges.ToString() +
" change(s) saved to the database.");
//forceChanges.Enabled = false;
}
catch (InvalidOperationException ioe)
{
MessageBox.Show(ioe.Message + " Click OK to retrieve "
+ "the latest data from the database.");
ExecuteInstructorQuery();
this.Refresh();
}
}
private void ExecuteInstructorQuery()
{
// Define the query to retrieve instructors.
ObjectQuery<Person> instructorQuery = schoolContext.Person
.Include("OfficeAssignment")
.Where("it.HireDate is not null")
.OrderBy("it.LastName");
//Execute and bind the instructorList control to the query.
//Using MergeOption.OverwriteChanges overwrites local data
//with data from the database.
instructorList.DataSource = instructorQuery
.Execute(MergeOption.OverwriteChanges);
instructorList.DisplayMember = "LastName";
}
}
}
Nächste Schritte
Sie haben gespeicherten Prozeduren erfolgreich Einfüge-, Aktualisierungs- und Löschvorgänge einer Entität zugeordnet. Weitere Informationen zu der Unterstützung von gespeicherten Prozeduren in Entity Framework finden Sie unter Unterstützung für gespeicherte Prozeduren (Entity Framework). Weitere Informationen zum Erstellen von Anwendungen, die Entity Framework verwenden, finden Sie unter Programmierhandbuch (Entity Framework).
Siehe auch
Weitere Ressourcen
Szenarios für den ADO.NET Entity Data Model-Designer
Aufgaben der Entity Data Model-Tools