Condividi tramite


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à.

Cc716679.note(it-it,VS.100).gifNota:
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.

Cc716679.note(it-it,VS.100).gifNota:
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.

Cc716679.note(it-it,VS.100).gifNota:
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

  1. Aprire la soluzione CourseManager in Visual Studio.

  2. 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).

  3. 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.

  4. 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.

  5. 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à.

  6. Fare clic su <Aggiungi Result Binding>.

    Il campo diventa modificabile.

  7. 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.

  8. 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à.

  9. 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

  1. 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.

  2. 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à.

  3. Fare clic su <Aggiungi Result Binding>.

    Il campo diventa modificabile.

  4. Digitare Timestamp.

  5. 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.

  6. Selezionare Timestamp dall'elenco a discesa.

  7. 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.

  8. 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à.

  9. 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.

  10. Fare clic su <Aggiungi Result Binding>.

    Il campo diventa modificabile.

  11. Sostituire <Aggiungi Result Binding> con Timestamp.

  12. 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.

  13. Selezionare Timestamp dall'elenco a discesa.

  14. 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

  1. 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.

  2. 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.

  3. Trascinare un controllo DataGridView dalla casella degli strumenti nel form e impostare il valore di Nome su instructorGridView nella finestra Proprietà.

  4. 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.

  5. 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.

  6. 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.

  7. 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.

  8. Trascinare un controllo ComboBox dalla casella degli strumenti nel form e impostare il valore di Nome su instructorList.

  9. Trascinare un controllo TextBox dalla casella degli strumenti nel form e impostare il valore di Nome su officeLocation.

  10. 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.

  11. In Esplora soluzioni fare doppio clic su CourseViewer.vb o su CourseViewer.cs.

    Verrà aperta la visualizzazione Progettazione del form CourseViewer.

  12. Trascinare un controllo Button dalla casella degli strumenti nel form.

  13. Nella finestra Proprietà impostare la proprietà Nome di Button su viewInstructors e la proprietà Testo su View Instructors.

  14. Fare doppio clic sul controllo viewInstructors Button.

    Verrà visualizzato il file code-behind per il form CourseViewer.

  15. Aggiungere il codice seguente al gestore eventi viewInstructors_Click:

    Dim instructorViewer As New InstructorViewer()
    instructorViewer.Visible = True
    
    InstructorViewer instructorViewer = new InstructorViewer();
    instructorViewer.Visible = true;
    
  16. Tornare alla visualizzazione Progettazione del form InstructorViewer.

  17. Fare doppio clic sul controllo viewOffices Button.

    Verrà visualizzato il file code-behind per Form2.

  18. 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

  1. 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.

  2. 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;
    
  3. 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;
    
  4. 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;
    
  5. 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.

  6. 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

  1. 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.

  2. 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;
    
  3. 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;
    
  4. 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.

  5. 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();
    
  6. 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.

  7. 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;
    
  8. 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.

  9. 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;
    }
    
  10. 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.

  11. 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

  1. Fare doppio clic su InstructorViewer.vb o su InstructorViewer.cs in Esplora soluzioni.

    Il form verrà aperto nella finestra di progettazione dei form.

  2. Fare doppio clic sul pulsante View Offices.

    Verrà visualizzato il file code-behind per il form InstructorViewer.

  3. 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;
    
  4. Fare doppio clic su OfficeViewer.vb o su OfficeViewer.cs in Esplora soluzioni.

    Il form verrà aperto nella finestra di progettazione dei form.

  5. 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.

  6. Fare doppio clic sul pulsante Force Changes.

    Verrà visualizzato il file code-behind per il form Office Viewer.

  7. 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();
    }
    
  8. Rimuovere il commento della riga di codice forceChanges = False (Visual Basic) o forceChanges = false; (C#) nel gestore eventi instructorList_SelectedIndexChanged in modo che il pulsante Force Changes venga disabilitato in seguito alla selezione di un nuovo docente.

  9. Rimuovere il commento della riga di codice forceChanges = True (Visual Basic) o forceChanges = true; (C#) nel gestore eventi updateOffice_Click in modo che il pulsante Force Changes venga abilitato in presenza di un conflitto di concorrenza.

  10. Rimuovere il commento della riga di codice forceChanges = False (Visual Basic) o forceChanges = 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