Procedura dettagliata: gestione di un'eccezione di concorrenza
Data di pubblicazione: aprile 2016
Le eccezioni di concorrenza (DBConcurrencyException) vengono generate quando due utenti tentano di modificare gli stessi dati di un database contemporaneamente. In questa procedura dettagliata verrà creata un'applicazione Windows che illustra l'intercettazione di un'eccezione DBConcurrencyException mediante l'individuazione della riga che ha causato l'errore e una strategia per la relativa gestione.
In questa procedura dettagliata vengono illustrati i seguenti passaggi:
Creazione di un nuovo progetto Applicazione Windows.
Creazione di un nuovo dataset basato sulla tabella Northwind
Customers
.Creazione di un form contenente un oggetto DataGridView per la visualizzazione dei dati.
Riempimento di un dataset con i dati contenuti nella tabella
Customers
del database Northwind.Dopo aver compilato il dataset, utilizzo degli Visual Database Tools in Visual Studio per accedere direttamente alla tabella di dati
Customers
e modificare un record.Nel form, modifica del valore dello stesso record, aggiornamento del dataset e tentativo di scrivere le modifiche nel database con conseguente generazione di un errore di concorrenza.
Intercettazione dell'errore e successiva visualizzazione delle diverse versioni del record per consentire all'utente di scegliere se continuare e aggiornare il database oppure annullare l'aggiornamento.
Prerequisiti
Per completare questa procedura dettagliata, è necessario quanto segue:
- Accedere al database di esempio Northwind con l'autorizzazione per l'esecuzione degli aggiornamenti. Per ulteriori informazioni, vedere Procedura: installare database di esempio.
Nota
È possibile che le finestre di dialogo e i comandi di menu visualizzati siano diversi da quelli descritti nella Guida a seconda delle impostazioni attive o dell'edizione del programma. Per modificare le impostazioni, scegliere Importa/esporta impostazioni dal menu Strumenti. Per ulteriori informazioni, vedere Customizing Development Settings in Visual Studio.
Creazione di un nuovo progetto
La prima parte della procedura dettagliata consiste nella creazione di una nuova applicazione Windows.
Per creare un nuovo progetto di applicazione Windows
Scegliere il comando per la creazione di un nuovo progetto dal menu File.
Selezionare un linguaggio di programmazione nel riquadro Tipi progetto.
Selezionare Applicazione Windows nel riquadro Modelli.
Assegnare al progetto il nome
ConcurrencyWalkthrough
, quindi scegliere OK.Il progetto verrà aggiunto a Esplora soluzioni e nella finestra di progettazione verrà visualizzato un nuovo form.
Creazione del dataset Northwind
In questa sezione verrà creato un dataset denominato NorthwindDataSet
.
Per creare il dataset NorthwindDataSet
Scegliere Aggiungi nuova origine dati dal menu Dati.
Verrà visualizzata la Configurazione guidata origine dati.
Selezionare Database nella pagina Seleziona un tipo di origine dati.
Selezionare una connessione al database di esempio Northwind dall'elenco delle connessioni disponibili oppure fare clic su Nuova connessione se la connessione non è disponibile nell'elenco delle connessioni.
Nota
Se si sta effettuando la connessione a un file del database locale, selezionare No quando viene chiesto se si desidera aggiungere il file al progetto.
Scegliere Avanti nella pagina Salva stringa di connessione nel file di configurazione dell'applicazione.
Espandere il nodo Tabelle e selezionare la tabella
Customers
. Il nome predefinito del dataset dovrebbe essereNorthwindDataSet
.Scegliere Fine per aggiungere il dataset al progetto.
Creazione di un controllo DataGridView con associazione a dati
In questa sezione verrà creato un oggetto DataGridView mediante il trascinamento dell'elemento Customers dalla finestra Origini dati sul Windows Form.
Per creare un controllo DataGridView associato alla tabella Customers
Scegliere Mostra origini dati dal menu Dati per aprire la finestra Origini dati.
Dalla finestra Origini dati espandere il nodo NorthwindDataSet e selezionare la tabella Customers.
Fare clic sulla freccia GIÙ sul nodo della tabella e selezionare DataGridView dall'elenco a discesa.
Trascinare la tabella in un'area vuota del form.
Al form associato all'oggetto BindingSource, che a sua volta è associato alla tabella
Customers
del datasetNorthwindDataSet
, verranno aggiunti un controllo DataGridView denominatoCustomersDataGridView
e un controllo BindingNavigator denominatoCustomersBindingNavigator
.
Verifica
È ora possibile verificare il form per assicurarsi che funzioni come previsto fino a questo punto.
Per eseguire il test del form
Premere F5 per eseguire l'applicazione.
Verrà visualizzato un form contenente un controllo DataGridView compilato con dati provenienti dalla tabella
Customers
.Scegliere Termina debug dal menu Debug.
Gestione degli errori di concorrenza
La gestione degli errori dipende dalle specifiche regole business che governano l'applicazione. In questa procedura dettagliata, dopo che è stata generata una violazione di concorrenza, verrà utilizzata a scopo esemplificativo la strategia descritta di seguito per gestire l'errore di concorrenza.
Tramite l'applicazione verranno presentate all'utente tre versioni del record:
Il record corrente nel database.
Il record originale caricato nel dataset.
Le modifiche proposte nel dataset.
L'utente sarà quindi in grado di sovrascrivere il database con la versione proposta oppure di annullare l'aggiornamento e aggiornare il dataset con i nuovi valori provenienti dal database.
Per attivare la gestione degli errori di concorrenza
Creare un gestore errori personalizzato.
Visualizzare le opzioni all'utente.
Elaborare la risposta dell'utente.
Inviare nuovamente l'aggiornamento o reimpostare i dati nel dataset.
Aggiunta di codice per gestire le eccezioni di concorrenza
Quando viene generata un'eccezione in seguito a un tentativo di aggiornamento, generalmente si desidera rispondere all'eccezione utilizzando le informazioni da essa fornite.
In questa sezione verrà aggiunto del codice per tentare di aggiornare il database e di gestire qualsiasi eccezione DBConcurrencyException generata, come pure qualunque altra eccezione.
Nota
I metodi CreateMessage
e ProcessDialogResults
verranno aggiunti nei passaggi successivi della procedura dettagliata.
Per aggiungere la gestione dell'errore di concorrenza
Aggiungere al metodo
Form1_Load
il seguente codice: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."); } }
Private Sub UpdateDatabase() Try Me.CustomersTableAdapter.Update(Me.NorthwindDataSet.Customers) MsgBox("Update successful") Catch dbcx As Data.DBConcurrencyException Dim response As Windows.Forms.DialogResult response = MessageBox.Show(CreateMessage(CType(dbcx.Row, NorthwindDataSet.CustomersRow)), "Concurrency Exception", MessageBoxButtons.YesNo) ProcessDialogResult(response) Catch ex As Exception MsgBox("An error was thrown while attempting to update the database.") End Try End Sub
Sostituire il metodo
CustomersBindingNavigatorSaveItem_Click
per chiamare il metodoUpdateDatabase
in modo che rispecchi l'esempio seguente:private void customersBindingNavigatorSaveItem_Click(object sender, EventArgs e) { UpdateDatabase(); }
Private Sub CustomersBindingNavigatorSaveItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CustomersBindingNavigatorSaveItem.Click UpdateDatabase() End Sub
Visualizzazione delle opzioni all'utente
Il codice sopra riportato consente di chiamare la routine CreateMessage
per visualizzare all'utente le informazioni sull'errore. Per questa procedura dettagliata verrà utilizzata una finestra di messaggio nella quale verranno visualizzate le diverse versioni del record, consentendo così all'utente di scegliere se sovrascrivere il record con le modifiche oppure annullare le modifiche apportate. In seguito alla selezione di un'opzione (mediante pressione di un pulsante) nella finestra di messaggio, la risposta verrà passata al metodo ProcessDialogResult
.
Per creare il messaggio da visualizzare all'utente
Creare il messaggio aggiungendo il codice che segue all'editor di codice. Immettere questo codice sotto al metodo
UpdateDatabase
.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; }
Private Function CreateMessage(ByVal cr As NorthwindDataSet.CustomersRow) As String Return "Database: " & GetRowData(GetCurrentRowInDB(cr), Data.DataRowVersion.Default) & vbCrLf & "Original: " & GetRowData(cr, Data.DataRowVersion.Original) & vbCrLf & "Proposed: " & GetRowData(cr, Data.DataRowVersion.Current) & vbCrLf & "Do you still want to update the database with the proposed value?" End Function '-------------------------------------------------------------------------- ' 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 TempCustomersDataTable As New NorthwindDataSet.CustomersDataTable Private Function GetCurrentRowInDB( ByVal RowWithError As NorthwindDataSet.CustomersRow ) As NorthwindDataSet.CustomersRow Me.CustomersTableAdapter.Fill(TempCustomersDataTable) Dim currentRowInDb As NorthwindDataSet.CustomersRow = TempCustomersDataTable.FindByCustomerID(RowWithError.CustomerID) Return currentRowInDb End Function '-------------------------------------------------------------------------- ' This method takes a CustomersRow and RowVersion ' and returns a string of column values to display to the user. '-------------------------------------------------------------------------- Private Function GetRowData(ByVal custRow As NorthwindDataSet.CustomersRow, ByVal RowVersion As Data.DataRowVersion) As String Dim rowData As String = "" For i As Integer = 0 To custRow.ItemArray.Length - 1 rowData &= custRow.Item(i, RowVersion).ToString() & " " Next Return rowData End Function
Elaborazione della risposta dell'utente
Sarà inoltre necessario il codice per elaborare la risposta dell'utente alla finestra di messaggio. L'utente potrà sovrascrivere il record corrente nel database con la modifica proposta o ignorare le modifiche locali e aggiornare la tabella dati con il record attualmente presente nel database. Se l'utente sceglie sì, il metodo Merge viene chiamato con l'argomento preserveChanges impostato su true
. Di conseguenza l'aggiornamento verrà eseguito, poiché la versione originale del record corrisponderà ora al record del database.
Per elaborare l'input dell'utente dalla finestra di messaggio
Aggiungere il codice che segue al di sotto del 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; } }
' 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 Sub ProcessDialogResult(ByVal response As Windows.Forms.DialogResult) Select Case response Case Windows.Forms.DialogResult.Yes NorthwindDataSet.Customers.Merge(TempCustomersDataTable, True) UpdateDatabase() Case Windows.Forms.DialogResult.No NorthwindDataSet.Customers.Merge(TempCustomersDataTable) MsgBox("Update cancelled") End Select End Sub
Test
È ora possibile verificare il form per assicurarsi che funzioni correttamente. Per simulare una violazione di concorrenza è necessario modificare i dati del database dopo aver riempito l'oggetto NorthwindDataSet.
Per eseguire il test del form
Premere F5 per eseguire l'applicazione.
Una volta visualizzato il form, consentirne l'esecuzione e passare all'ambiente di sviluppo integrato (IDE) di Visual Studio.
Scegliere Esplora server dal menu Visualizza.
In Esplora server espandere la connessione utilizzata dall'applicazione, quindi il nodo Tabelle.
Fare clic con il pulsante destro del mouse sulla tabella Customers e selezionare Mostra dati tabella.
Nel primo record (
ALFKI
) modificareContactName
conMaria Anders2
.Nota
Passare a un'altra riga per eseguire il commit della modifica.
Passare al form in esecuzione del progetto
ConcurrencyWalkthrough
.Nel primo record del form (
ALFKI
) modificareContactName
conMaria Anders1
.Fare clic sul pulsante Salva.
Verrà generato l'errore di concorrenza e verrà visualizzata la finestra di messaggio.
Se si sceglie No l'aggiornamento verrà annullato e il dataset verrà aggiornato con i valori correntemente presenti nel database, mentre se si sceglie Sì il valore proposto verrà scritto nel database.
Vedere anche
Procedure dettagliate relative ai dati
Associazione di controlli Windows Form ai dati in Visual Studio
Connessione ai dati in Visual Studio
Preparazione dell'applicazione al ricevimento di dati
Recupero di dati nell'applicazione
Associazione di controlli ai dati in Visual Studio
Modifica di dati nell'applicazione
Convalida dei dati
Salvataggio di dati