Gestire un'eccezione di concorrenza nelle applicazioni di database .NET Framework

Nota

I set di dati e le classi correlate sono tecnologie .NET Framework legacy dei primi anni '2000 che consentono alle applicazioni di lavorare con i dati in memoria mentre le applicazioni vengono disconnesse dal database. Sono particolarmente utili per le applicazioni che consentono agli utenti di modificare i dati e rendere persistenti le modifiche apportate al database. Anche se i set di dati hanno dimostrato di essere una tecnologia molto efficace, è consigliabile che le nuove applicazioni .NET usino Entity Framework Core. Entity Framework offre un modo più naturale per usare i dati tabulari come modelli a oggetti e ha un'interfaccia di programmazione più semplice.

Le eccezioni di concorrenza (System.Data.DBConcurrencyException) vengono generate quando due utenti tentano di modificare contemporaneamente gli stessi dati in un database. In questa procedura dettagliata si crea un'applicazione Windows che illustra come intercettare un DBConcurrencyExceptionoggetto , individuare la riga che ha causato l'errore e apprendere una strategia per gestirla.

Questa procedura dettagliata illustra il processo seguente:

  1. Creare un nuovo progetto app Windows Form (.NET Framework).

  2. Creare un nuovo set di dati basato sulla tabella Northwind Customers.

  3. Creare un modulo con un DataGridView oggetto per visualizzare i dati.

  4. Compilare un set di dati con i dati della tabella Customers nel database Northwind.

  5. Utilizzare la funzionalità Mostra dati tabella in Esplora server per accedere ai dati della tabella Customers e modificare un record.

  6. Modificare lo stesso record in un valore diverso, aggiornare il set di dati e tentare di scrivere le modifiche nel database, che genera un errore di concorrenza.

  7. Intercettare l'errore, quindi visualizzare le diverse versioni del record, consentendo all'utente di determinare se continuare e aggiornare il database o annullare l'aggiornamento.

Prerequisiti

Questa procedura dettagliata usa sql Server Express Local DB e il database di esempio Northwind.

  1. Se SQL Server Express Local DB non è disponibile, installarlo dalla pagina di download di SQL Server Express o tramite il Programma di installazione di Visual Studio. Nella Programma di installazione di Visual Studio è possibile installare SQL Server Express Local DB come parte del carico di lavoro Archiviazione ed elaborazione dei dati o come singolo componente.

  2. Installare il database di esempio Northwind seguendo questa procedura:

    1. In Visual Studio aprire la finestra Esplora oggetti di SQL Server. SQL Server Esplora oggetti viene installato come parte del carico di lavoro Archiviazione ed elaborazione dei dati nel Programma di installazione di Visual Studio. Espandere il nodo SQL Server. Fare clic con il pulsante destro del mouse sull'istanza di Local DB e scegliere Nuova query.

      Verrà visualizzata una finestra dell'editor di query.

    2. Copiare lo script Transact-SQL Northwind negli Appunti. Questo script T-SQL crea il database Northwind da zero e lo popola con i dati.

    3. Incollare lo script T-SQL nell'editor di query e quindi scegliere il pulsante Esegui .

      Dopo un breve periodo di tempo, la query termina l'esecuzione e viene creato il database Northwind.

Crea un nuovo progetto

Per iniziare, creare una nuova applicazione Windows Form:

  1. Nel menu File in Visual Studio selezionare Nuovo>Progetto.

  2. Espandere Visual C# o Visual Basic nel riquadro a sinistra, quindi selezionare Desktop di Windows.

  3. Nel riquadro centrale selezionare il tipo di progetto Windows Form app.

  4. Assegnare al progetto il nome ConcurrencyWalkthrough e quindi scegliere OK.

    Il progetto ConcurrencyWalkthrough viene creato e aggiunto a Esplora soluzioni e viene aperto un nuovo modulo nella finestra di progettazione.

Creare il set di dati Northwind

Creare quindi un set di dati denominato NorthwindDataSet:

  1. Scegliere Aggiungi nuova origine dati dal menu Dati.

    Viene avviata la Configurazione guidata origine dati.

  2. Nella schermata Scegliere un tipo di origine dati selezionare Database.

    Configurazione guidata origine dati in Visual Studio

  3. Selezionare una connessione al database di esempio Northwind dall'elenco delle connessioni disponibili. Se la connessione non è disponibile nell'elenco delle connessioni, selezionare Nuovo Connessione ion.

    Nota

    Se ci si connette a un file di database locale, selezionare No quando viene chiesto se si vuole aggiungere il file al progetto.

  4. Nella schermata Salva stringa di connessione nel file di configurazione dell'applicazione selezionare Avanti.

  5. Espandere il nodo Tabelle e selezionare la tabella Clienti . Il nome predefinito per il set di dati deve essere NorthwindDataSet.

  6. Selezionare Fine per aggiungere il set di dati al progetto.

Creare un controllo DataGridView associato a dati

In questa sezione viene creato un System.Windows.Forms.DataGridView oggetto trascinando l'elemento Customers dalla finestra Origini dati nel Windows Form.

  1. Per aprire la finestra Origini dati, scegliere Mostra origini dati dal menu Dati.

  2. Nella finestra Origini dati espandere il nodo NorthwindDataSet e quindi selezionare la tabella Customers.

  3. Selezionare la freccia giù nel nodo della tabella e quindi selezionare DataGridView nell'elenco a discesa.

  4. Trascinare la tabella in un'area vuota del form.

    Un DataGridView controllo denominato CustomersDataGridView e un BindingNavigator oggetto CustomersBindingNavigator denominato vengono aggiunti al form associato a BindingSource. Questo è, a sua volta, associato alla tabella Customers in NorthwindDataSet.

Verificare il modulo

È ora possibile testare il modulo per assicurarsi che si comporti come previsto fino a questo punto:

  1. Selezionare F5 per eseguire l'applicazione.

    Il modulo viene visualizzato con un DataGridView controllo su di esso compilato con i dati della tabella Customers.

  2. Selezionare Arresta debug dal menu Debug.

Gestire gli errori di concorrenza

La modalità di gestione degli errori dipende dalle regole business specifiche che regolano l'applicazione. Per questa procedura dettagliata viene usata la strategia seguente come esempio per gestire l'errore di concorrenza.

L'applicazione presenta all'utente tre versioni del record:

  • Record corrente nel database

  • Record originale caricato nel set di dati

  • Modifiche proposte nel set di dati

L'utente può quindi sovrascrivere il database con la versione proposta oppure annullare l'aggiornamento e aggiornare il set di dati con i nuovi valori del database.

Per abilitare la gestione degli errori di concorrenza

  1. Creare un gestore degli errori personalizzato.

  2. Consente di visualizzare le scelte per l'utente.

  3. Elaborare la risposta dell'utente.

  4. Inviare nuovamente l'aggiornamento o reimpostare i dati nel set di dati.

Aggiungere codice per gestire l'eccezione di concorrenza

Quando si tenta di eseguire un aggiornamento e viene generata un'eccezione, in genere si vuole eseguire un'operazione con le informazioni fornite dall'eccezione generata. In questa sezione viene aggiunto codice che tenta di aggiornare il database. È anche possibile gestire eventuali DBConcurrencyException eccezioni che potrebbero essere generate, nonché qualsiasi altra eccezione.

Nota

I CreateMessage metodi e ProcessDialogResults vengono aggiunti più avanti nella procedura dettagliata.

  1. Aggiungere il codice seguente sotto il Form1_Load metodo :

    private void UpdateDatabase()
    {
        try
        {
            this.customersTableAdapter.Update(this.northwindDataSet.Customers);
            MessageBox.Show("Update successful");
        }
        catch (DBConcurrencyException dbcx)
        {
            DialogResult response = MessageBox.Show(CreateMessage((NorthwindDataSet.CustomersRow)
                (dbcx.Row)), "Concurrency Exception", MessageBoxButtons.YesNo);
    
            ProcessDialogResult(response);
        }
        catch (Exception ex)
        {
            MessageBox.Show("An error was thrown while attempting to update the database.");
        }
    }
    

  1. Sostituire il CustomersBindingNavigatorSaveItem_Click metodo per chiamare il UpdateDatabase metodo in modo che abbia un aspetto simile al seguente:

    private void customersBindingNavigatorSaveItem_Click(object sender, EventArgs e)
    {
        UpdateDatabase();
    }
    

Visualizzare le scelte per l'utente

Il codice appena scritto chiama la CreateMessage procedura per visualizzare le informazioni sull'errore all'utente. Per questa procedura dettagliata, si usa una finestra di messaggio per visualizzare le diverse versioni del record all'utente. In questo modo l'utente può scegliere se sovrascrivere il record con le modifiche o annullare la modifica. Quando l'utente seleziona un'opzione (fa clic su un pulsante) nella finestra di messaggio, la risposta viene passata al ProcessDialogResult metodo .

Creare il messaggio aggiungendo il codice seguente all'editor di codice. Immettere questo codice sotto il UpdateDatabase metodo :

private string CreateMessage(NorthwindDataSet.CustomersRow cr)
{
    return
        "Database: " + GetRowData(GetCurrentRowInDB(cr), DataRowVersion.Default) + "\n" +
        "Original: " + GetRowData(cr, DataRowVersion.Original) + "\n" +
        "Proposed: " + GetRowData(cr, DataRowVersion.Current) + "\n" +
        "Do you still want to update the database with the proposed value?";
}


//--------------------------------------------------------------------------
// This method loads a temporary table with current records from the database
// and returns the current values from the row that caused the exception.
//--------------------------------------------------------------------------
private NorthwindDataSet.CustomersDataTable tempCustomersDataTable = 
    new NorthwindDataSet.CustomersDataTable();

private NorthwindDataSet.CustomersRow GetCurrentRowInDB(NorthwindDataSet.CustomersRow RowWithError)
{
    this.customersTableAdapter.Fill(tempCustomersDataTable);

    NorthwindDataSet.CustomersRow currentRowInDb = 
        tempCustomersDataTable.FindByCustomerID(RowWithError.CustomerID);

    return currentRowInDb;
}


//--------------------------------------------------------------------------
// This method takes a CustomersRow and RowVersion 
// and returns a string of column values to display to the user.
//--------------------------------------------------------------------------
private string GetRowData(NorthwindDataSet.CustomersRow custRow, DataRowVersion RowVersion)
{
    string rowData = "";

    for (int i = 0; i < custRow.ItemArray.Length ; i++ )
    {
        rowData = rowData + custRow[i, RowVersion].ToString() + " ";
    }
    return rowData;
}

Elaborare la risposta dell'utente

È anche necessario codice per elaborare la risposta dell'utente alla finestra di messaggio. Le opzioni consentono di sovrascrivere il record corrente nel database con la modifica proposta oppure di abbandonare le modifiche locali e aggiornare la tabella dati con il record attualmente presente nel database. Se l'utente sceglie , il Merge metodo viene chiamato con l'argomento preserveChanges impostato su true. In questo modo il tentativo di aggiornamento ha esito positivo, perché la versione originale del record corrisponde ora al record nel database.

Aggiungere il codice seguente sotto il codice aggiunto nella sezione precedente:

// This method takes the DialogResult selected by the user and updates the database 
// with the new values or cancels the update and resets the Customers table 
// (in the dataset) with the values currently in the database.

private void ProcessDialogResult(DialogResult response)
{
    switch (response)
    {
        case DialogResult.Yes:
            northwindDataSet.Merge(tempCustomersDataTable, true, MissingSchemaAction.Ignore);
            UpdateDatabase();
            break;

        case DialogResult.No:
            northwindDataSet.Merge(tempCustomersDataTable);
            MessageBox.Show("Update cancelled");
            break;
    }
}

Testare il comportamento del modulo

È ora possibile testare il modulo per assicurarsi che si comporti come previsto. Per simulare una violazione della concorrenza, modificare i dati nel database dopo aver compilato NorthwindDataSet.

  1. Selezionare F5 per eseguire l'applicazione.

  2. Dopo aver visualizzato il modulo, lasciarlo in esecuzione e passare all'IDE di Visual Studio.

  3. Scegliere Esplora server dal menu Visualizza.

  4. In Esplora server espandere la connessione usata dall'applicazione e quindi espandere il nodo Tabelle .

  5. Fare clic con il pulsante destro del mouse sulla tabella Customers e quindi scegliere Mostra dati tabella.

  6. Nel primo record (ALFKI) modificare ContactName in Maria Anders2.

    Nota

    Passare a una riga diversa per eseguire il commit della modifica.

  7. Passare al modulo in esecuzione di ConcurrencyWalkthrough.

  8. Nel primo record nel modulo (ALFKI), modificare ContactName in Maria Anders1.

  9. Selezionare il pulsante Salva.

    Viene generato l'errore di concorrenza e viene visualizzata la finestra di messaggio.

    Selezionando No annulla l'aggiornamento e aggiorna il set di dati con i valori attualmente presenti nel database. Se si seleziona , il valore proposto viene scritto nel database.