Procedura dettagliata: mapping di un'entità alle stored procedure (strumenti di Entity Data Model)
In questo argomento viene illustrato come utilizzare ADO.NET Entity Data Model Designer (Entity Designer) per eseguire il mapping delle operazioni di inserimento, aggiornamento ed eliminazione di un tipo di entità alle stored procedure. Per le operazioni di inserimento, aggiornamento ed eliminazione di un tipo di entità è possibile utilizzare le istruzioni SQL generate automaticamente dal sistema (impostazione predefinita) o le stored procedure specificate dallo sviluppatore. Il codice dell'applicazione utilizzato per creare, aggiornare ed eliminare le entità è identico indipendentemente dall'uso o meno delle stored procedure per aggiornare il database.
In questa procedura dettagliata si eseguirà il mapping di due tipi di entità nel modello concettuale alle stored procedure nel modello di archiviazione modificando il file con estensione edmx utilizzato nell'applicazione CourseManager. Per ulteriori informazioni, vedere la sezione Prerequisiti più avanti in questo argomento. Verrà anche scritto codice per inserire, aggiornare ed eliminare i tipi di entità.
Nota: |
---|
Se non si esegue il mapping di tutte e tre le operazioni di inserimento, aggiornamento ed eliminazione di un tipo di entità alle stored procedure, le operazioni non mappate avranno esito negativo se eseguite in fase di esecuzione e verrà generata un'eccezione UpdateException. |
Prerequisiti
Per completare questa procedura dettagliata è necessario compilare l'applicazione CourseManager. Per ulteriori informazioni e istruzioni, vedere la Guida rapida di Entity Framework. Dopo avere compilato l'applicazione, ne verrà modificato il file con estensione edmx eseguendo il mapping di due tipi di entità alle stored procedure.
Nota: |
---|
Dal momento che in molti argomenti contenenti procedure dettagliate di questa documentazione viene utilizzata l'applicazione CourseManager come punto di partenza, è consigliabile utilizzare una copia di tale applicazione anziché modificarne il codice originale. |
In questa procedura dettagliata si presuppone che il lettore disponga di una competenza di base di Visual Studio, .NET Framework e della programmazione in Visual C# o Visual Basic.
Mapping dell'entità Person alle stored procedure
Quando si esegue il mapping dell'operazione di inserimento di un'entità a una stored procedure, se il server crea il valore della chiave primaria per la riga inserita, è necessario rieseguire il mapping di tale valore alla proprietà della chiave dell'entità. In questo esempio la stored procedure InsertPerson restituisce la chiave primaria appena creata come parte del set di risultati della stored procedure. Viene eseguito il mapping della chiave primaria alla chiave di entità (PersonID) utilizzando la funzionalità <Aggiungi Result Binding> di Entity Designer.
Nota: |
---|
Se si esegue il mapping di un'operazione di inserimento, aggiornamento o eliminazione a una stored procedure che restituisce un parametro di output con valore Integer, la casella di controllo Parametro delle righe interessate è abilitata.Se la casella di controllo viene selezionata per un parametro e il valore restituito quando viene chiamata l'operazione di aggiornamento è zero, verrà generata un'eccezione OptimisticConcurrencyException. |
Per eseguire il mapping dell'entità Person alle stored procedure
Aprire la soluzione CourseManager in Visual Studio.
In Esplora soluzioni fare doppio clic sul file School.edmx.
Il file School.edmx verrà aperto in ADO.NET Entity Data Model Designer (Entity Designer).
Fare clic con il pulsante destro del mouse sul tipo di entità Person e selezionare Mapping stored procedure.
I mapping delle stored procedure vengono visualizzati nella finestra Dettagli Mapping.
Fare clic su <Seleziona Insert Function>.
Questo campo diventa l'elenco a discesa delle stored procedure contenute nel modello di archiviazione che possono essere mappate ai tipi di entità del modello concettuale.
Selezionare InsertPerson dall'elenco a discesa.
Vengono visualizzati i mapping predefiniti tra i parametri delle stored procedure e le proprietà dell'entità. Come indicato dalle frecce, che mostrano la direzione del mapping, per i parametri delle stored procedure vengono specificati i valori delle proprietà.
Fare clic su <Aggiungi Result Binding>.
Il campo diventa modificabile.
Digitare NewPersonID, il nome del parametro restituito dalla stored procedure InsertPerson. Premere Invio.
Per impostazione predefinita, viene eseguito il mapping di NewPersonID alla chiave di entità PersonID. Come indicato dalle frecce, che mostrano la direzione del mapping, per la proprietà viene specificato il valore della colonna dei risultati.
Fare clic su <Seleziona Update Function> e selezionare UpdatePerson dall'elenco a discesa risultante.
Vengono visualizzati i mapping predefiniti tra i parametri delle stored procedure e le proprietà dell'entità.
Fare clic su <Seleziona Delete Function> e selezionare DeletePerson dall'elenco a discesa risultante.
Vengono visualizzati i mapping predefiniti tra i parametri delle stored procedure e le proprietà dell'entità.
Viene ora eseguito il mapping delle operazioni di inserimento, aggiornamento ed eliminazione del tipo di entità Person alle stored procedure.
Mapping dell'entità OfficeAssignment alle stored procedure
In questo esempio, mappare il tipo di entità OfficeAssignment alle stored procedure. In questo mapping si utilizza l'opzione Utilizza Original Value per l'operazione di aggiornamento allo scopo di semplificare il controllo della concorrenza nel codice dell'applicazione.
Per eseguire il mapping dell'entità OfficeAssignment alle stored procedure
Fare clic con il pulsante destro del mouse sul tipo di entità OfficeAssignment e selezionare Stored Procedure Mapping.
I mapping delle stored procedure vengono visualizzati nella finestra Dettagli Mapping.
Fare clic su <Seleziona Insert Function> e selezionare InsertOfficeAssignment dall'elenco a discesa risultante.
Vengono visualizzati i mapping predefiniti tra i parametri delle stored procedure e le proprietà dell'entità.
Fare clic su <Aggiungi Result Binding>.
Il campo diventa modificabile.
Digitare Timestamp.
Fare clic sul campo vuoto nella colonna Property/Value accanto a Timestamp.
Il campo diventa un elenco a discesa di proprietà al quale è possibile mappare il valore restituito dalla stored procedure InsertOfficeAssignment.
Selezionare Timestamp dall'elenco a discesa.
Fare clic su <Seleziona Update Function> e selezionare UpdateOfficeAssignment dall'elenco a discesa risultante.
Vengono visualizzati i mapping predefiniti tra i parametri delle stored procedure e le proprietà dell'entità. Le caselle di controllo vengono visualizzate nella colonna Utilizza Original Value accanto a ogni proprietà di cui è stato eseguito il mapping.
Fare clic sul campo vuoto nella colonna Proprietà che corrisponde al parametro OrigTimestamp e selezionare Timestamp dall'elenco a discesa risultante.
Questo mapping non è stato impostato in Entity Designer come mapping predefinito perché il nome del parametro non corrispondeva esattamente al nome della proprietà.
Selezionare la casella nella colonna Utilizza Original Value corrispondente alla proprietà Timestamp.
Quando si tenta di eseguire un aggiornamento, il valore della proprietà Timestamp originariamente letta dal database verrà utilizzato durante la riscrittura dei dati nel database. Se il valore non corrisponde al valore nel database, verrà generata un'eccezione OptimisticConcurrencyException.
Fare clic su <Aggiungi Result Binding>.
Il campo diventa modificabile.
Sostituire <Aggiungi Result Binding> con Timestamp.
Fare clic sul campo vuoto nella colonna Property/Value accanto a Timestamp.
Il campo diventa un elenco a discesa di proprietà al quale è possibile mappare la colonna dei risultati restituita dalla stored procedure UpdateOfficeAssignment.
Selezionare Timestamp dall'elenco a discesa.
Fare clic su <Seleziona Delete Function> e selezionare DeleteOfficeAssignment dall'elenco a discesa risultante.
Vengono visualizzati i mapping predefiniti tra i parametri delle stored procedure e le proprietà dell'entità.
Viene ora eseguito il mapping delle operazioni di inserimento, aggiornamento ed eliminazione del tipo di entità OfficeAssignment alle stored procedure.
Costruzione dell'interfaccia utente
Si procederà quindi all'aggiunta di due form all'applicazione CourseManager. Un form fornisce un'interfaccia per la visualizzazione e l'aggiornamento delle informazioni sul docente. L'altro form fornisce un'interfaccia per la visualizzazione e l'aggiornamento delle assegnazioni degli uffici.
Per costruire l'interfaccia utente
Fare clic con il pulsante destro del mouse sul progetto CourseManager in Esplora soluzioni, scegliere Aggiungi, quindi selezionare Nuovo elemento.
Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento.
Selezionare Windows Form, impostare il nome del form su InstructorViewer.vb o InstructorViewer.cs e fare clic su Aggiungi.
Un nuovo form verrà aggiunto al progetto e aperto nella finestra di progettazione dei form. Il nome del form viene impostato su InstructorViewer, mentre il testo viene impostato su InstructorViewer.
Trascinare un controllo DataGridView dalla casella degli strumenti nel form e impostare il valore di Nome su instructorGridView nella finestra Proprietà.
Trascinare un controllo Button dalla casella degli strumenti nel form. Impostare il valore di Nome su updateInstructor e il valore di Testo su Update Instructor.
Trascinare un altro controllo Button dalla casella degli strumenti nel form. Impostare il valore di Nome su viewOffices e il valore di Testo su View Offices.
Fare clic con il pulsante destro del mouse sul progetto CourseManager in Esplora soluzioni, scegliere Aggiungi, quindi selezionare Nuovo elemento.
Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento.
Selezionare Windows Form, impostare il nome del form su OfficeViewer.vb o su OfficeViewer.cs, quindi fare clic su Aggiungi.
Un nuovo form verrà aggiunto al progetto e aperto nella finestra di progettazione dei form. Il nome del form viene impostato su OfficeViewer, mentre il testo viene impostato su OfficeViewer.
Trascinare un controllo ComboBox dalla casella degli strumenti nel form e impostare il valore di Nome su instructorList.
Trascinare un controllo TextBox dalla casella degli strumenti nel form e impostare il valore di Nome su officeLocation.
Trascinare un controllo Button dalla casella degli strumenti nel form. Impostare il valore di Nome su updateOffice e il valore di Testo su Update Office.
In Esplora soluzioni fare doppio clic su CourseViewer.vb o su CourseViewer.cs.
Verrà aperta la visualizzazione Progettazione del form CourseViewer.
Trascinare un controllo Button dalla casella degli strumenti nel form.
Nella finestra Proprietà impostare la proprietà Nome di Button su viewInstructors e la proprietà Testo su View Instructors.
Fare doppio clic sul controllo viewInstructors Button.
Verrà visualizzato il file code-behind per il form CourseViewer.
Aggiungere il codice seguente al gestore eventi viewInstructors_Click:
Dim instructorViewer As New InstructorViewer() instructorViewer.Visible = True
InstructorViewer instructorViewer = new InstructorViewer(); instructorViewer.Visible = true;
Tornare alla visualizzazione Progettazione del form InstructorViewer.
Fare doppio clic sul controllo viewOffices Button.
Verrà visualizzato il file code-behind per Form2.
Aggiungere il codice seguente al gestore eventi viewOffices_Click:
Dim officeViewer As New OfficeViewer() officeViewer.Visible = True
OfficeViewer officeViewer = new OfficeViewer(); officeViewer.Visible = true;
L'interfaccia utente è ora completa.
Visualizzazione e aggiornamento delle informazioni sul docente
In questa procedura si aggiungerà codice al form InstructorViewer che consente di visualizzare e aggiornare le informazioni sul docente. In particolare, il codice effettua le operazioni seguenti:
Associa DataGridView a una query che restituisce informazioni sui tipi Person con ruolo di docenti. Per ulteriori informazioni sull'associazione di oggetti ai controlli, vedere Binding Objects to Controls (Entity Framework).
Salva nel database eventuali modifiche (inserimenti, aggiornamenti o eliminazioni) nel controllo DataGridView.
Utilizza le stored procedure di cui è stato eseguito il mapping in precedenza per scrivere dati nel database quando SaveChanges() viene chiamato nel gestore eventi updateInstructor_Click.
Per visualizzare e aggiornare le informazioni sul docente
Fare doppio clic sul form InstructorViewer dopo averlo aperto nella finestra di progettazione dei form.
Verrà visualizzato il file code-behind per il form InstructorViewer.
Aggiungere le istruzioni using (C#) o Imports (Visual Basic) seguenti:
Imports System.Data.Objects Imports System.Data.Objects.DataClasses
using System.Data.Objects; using System.Data.Objects.DataClasses;
Aggiungere una proprietà alla classe InstructorViewer che rappresenta il contesto dell'oggetto:
' Create an ObjectContext instance based on SchoolEntity. Private schoolContext As SchoolEntities
// Create an ObjectContext instance based on SchoolEntity. private SchoolEntities schoolContext;
Nel gestore eventi InstructorViewer_Load aggiungere codice per inizializzare il contesto dell'oggetto e impostare l'origine dati per il controllo DataGridView su una query che restituisce tutti i tipi Person con attributo HireDate diverso da null.
' 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;
Tornare alla visualizzazione Progettazione del form InstructorViewer e fare doppio clic sul controllo updateInstructor Button.
Il gestore eventi updateInstructor_Click viene aggiunto al file code-behind.
Aggiungere codice al gestore eventi updateInstructor_Click per salvare le eventuali modifiche apportate alle informazioni sul docente nel controllo instructorGridView DataGridView.
' 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();
Premere CTRL+F5 per eseguire l'applicazione. Le informazioni sul docente possono ora essere visualizzate e aggiornate facendo clic su View Instructors, apportando modifiche nella tabella visualizzata e facendo clic su Update Instructor.
Visualizzazione e aggiornamento delle informazioni sull'ufficio
In questa procedura si aggiungerà codice al form OfficeViewer che consente di visualizzare e aggiornare informazioni sulle assegnazioni degli uffici. In particolare, il codice effettua le operazioni seguenti:
Associa ComboBox a una query che restituisce informazioni sul docente.
Visualizza informazioni sull'ubicazione dell'ufficio per il docente selezionato in TextBox.
Utilizza le stored procedure di cui è stato eseguito il mapping in precedenza per scrivere dati nel database quando SaveChanges() viene chiamato nel gestore eventi updateOffice_Click.
Per visualizzare e aggiornare le informazioni sull'ufficio
Fare doppio clic sul form OfficeViewer dopo averlo aperto nella finestra di progettazione dei form.
Verrà visualizzato il file code-behind per il form OfficeViewer.
Aggiungere le istruzioni using (C#) o Imports (Visual Basic) seguenti:
Imports System.Data.Objects Imports System.Data.Objects.DataClasses
using System.Data.Objects; using System.Data.Objects.DataClasses;
Aggiungere una proprietà alla classe OfficeViewer che rappresenta il contesto dell'oggetto:
' Create an ObjectContext instance based on SchoolEntity. Private schoolContext As SchoolEntities
// Create an ObjectContext instance based on SchoolEntity. private SchoolEntities schoolContext;
Aggiungere il metodo seguente al form:
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"; }
Questo metodo esegue una query che restituisce informazioni sul docente e associa i risultati al controllo instructorList ComboBox.
Nel gestore eventi OfficeViewer_Load aggiungere codice per inizializzare il contesto dell'oggetto e chiamare un metodo che associa il controllo ComboBox a una query che restituisce tutti i tipi Person con attributo HireDate diverso da null.
schoolContext = New SchoolEntities() ExecuteInstructorQuery()
schoolContext = new SchoolEntities(); ExecuteInstructorQuery();
Tornare alla visualizzazione Progettazione del form OfficeViewer e fare doppio clic sul controllo instructorList ComboBox.
Il gestore eventi instructorList_SelectedIndexChanged viene aggiunto al file code-behind.
Aggiungere codice al gestore eventi per visualizzare l'ubicazione dell'ufficio del docente selezionato nel controllo ListBox e disabilitare il controllo updateOffice Button. Questo controllo verrà attivato in seguito alla modifica dell'ubicazione dell'ufficio selezionata.
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;
Tornare alla visualizzazione Progettazione del form OfficeViewer e fare doppio clic sul controllo updateOffice Button.
Il gestore eventi updateOffice_Click viene aggiunto al file code-behind.
Aggiungere codice per salvare le modifiche apportate alle informazioni sull'ufficio nel controllo officeLocation TextBox:
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; }
Tornare alla visualizzazione Progettazione del form OfficeViewer e fare doppio clic sul controllo officeLocation TextBox.
Il gestore eventi officeLocation_TextChanged viene aggiunto al file code-behind.
Aggiungere codice per attivare il controllo updateOffice Button in seguito alla modifica dell'ubicazione dell'ufficio selezionata:
' 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;
L'applicazione è ora completa. Premere CTRL+F5 per eseguirla. È ora possibile visualizzare e aggiornare le informazioni sull'ufficio nel form OfficeViewer.
Gestione dei conflitti di concorrenza
In questa procedura si aggiungerà codice al form Office Viewer per forzare modifiche client al database in seguito a un conflitto di concorrenza.
Per gestire i conflitti di concorrenza
Fare doppio clic su InstructorViewer.vb o su InstructorViewer.cs in Esplora soluzioni.
Il form verrà aperto nella finestra di progettazione dei form.
Fare doppio clic sul pulsante View Offices.
Verrà visualizzato il file code-behind per il form InstructorViewer.
Aggiungere il codice seguente al gestore eventi viewOffices_Click in modo da caricare due form OfficeViewer quando si fa clic sul pulsante View Offices.
Dim officeViewer2 As New OfficeViewer() officeViewer2.Text = "Demonstrate Conflict" officeViewer2.Visible = True
OfficeViewer officeViewer2 = new OfficeViewer(); officeViewer2.Text = "Demonstrate Conflict"; officeViewer2.Visible = true;
Fare doppio clic su OfficeViewer.vb o su OfficeViewer.cs in Esplora soluzioni.
Il form verrà aperto nella finestra di progettazione dei form.
Trascinare un controllo Button dalla casella degli strumenti nel form. Impostare il valore di Nome su forceChanges e il valore di Testo su Force Changes.
Fare doppio clic sul pulsante Force Changes.
Verrà visualizzato il file code-behind per il form Office Viewer.
Aggiungere il codice seguente al gestore eventi forceChanges_Click in modo che le modifiche apportate al client verranno forzate sul server o i dati associati al controllo instructorList ComboBox verranno aggiornati dal database.
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(); }
Rimuovere il commento della riga di codice
forceChanges = False
(Visual Basic) oforceChanges = false;
(C#) nel gestore eventi instructorList_SelectedIndexChanged in modo che il pulsante Force Changes venga disabilitato in seguito alla selezione di un nuovo docente.Rimuovere il commento della riga di codice
forceChanges = True
(Visual Basic) oforceChanges = true;
(C#) nel gestore eventi updateOffice_Click in modo che il pulsante Force Changes venga abilitato in presenza di un conflitto di concorrenza.Rimuovere il commento della riga di codice
forceChanges = False
(Visual Basic) oforceChanges = false;
(C#) nel gestore eventi forceChanges_Click in modo che il pulsante Force Changes venga disabilitato in seguito alla modifica forzata del database.
Per verificare il modo in cui l'applicazione gestisce un conflitto di concorrenza, eseguire l'applicazione premendo CTRL+F5, fare clic su View Instructors, quindi su View Offices. Aggiornare un'ubicazione di ufficio nel form Office Viewer, quindi provare ad aggiornare la stessa ubicazione nell'altro form Demonstrate Conflict. Verrà visualizzata una finestra di messaggio in cui viene notificato il conflitto di concorrenza. Per forzare le modifiche dal form Demonstrate Conflict nel database, fare clic su Force Changes.
Listato di codice
In questa sezione sono contenute le versioni finali dei file code-behind per i form InstructorViewer e 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";
}
}
}
Passaggi successivi
È stato eseguito il mapping delle operazioni di inserimento, aggiornamento ed eliminazione di un'entità alle stored procedure. Per ulteriori informazioni sulla compilazione di applicazioni che utilizzano Entity Framework, vedere Entity Framework.
Vedere anche
Altre risorse
Scenari degli strumenti di Entity Data Model
Attività degli strumenti di Entity Data Model