Tutorial: Controlar una excepción de simultaneidad
Publicado: abril de 2016
Las excepciones de simultaneidad (DBConcurrencyException) se producen cuando dos usuarios intentan cambiar los mismos datos al mismo tiempo en una base de datos. En este tutorial creará una aplicación para Windows que ilustra cómo detectar una excepción DBConcurrencyException, ubicar la fila que produjo el error y una estrategia para controlarlo.
Este tutorial le guía a través del proceso siguiente:
Crear un proyecto nuevo de aplicación para Windows.
Crear un nuevo conjunto de datos basado en la tabla
Customers
de Northwind.Crear un formulario con un control DataGridView para mostrar los datos.
Llenar un conjunto de datos con datos de la tabla
Customers
de la base de datos Northwind.Después de rellenar el conjunto de datos, utilizar Visual Database Tools en Visual Studio para tener acceso directamente a la tabla de datos
Customers
y cambiar un registro.A continuación, en el formulario, cambiar el mismo registro a un valor diferente, actualizar el conjunto de datos e intentar escribir los cambios en la base de datos, lo que hará que surja un error de simultaneidad.
Detectar el error y luego mostrar las diferentes versiones del registro, de modo que el usuario pueda determinar si continuar y actualizar la base de datos o cancelar la actualización.
Requisitos previos
Para completar las tareas de este tutorial, necesitará:
- Acceso a la base de datos de ejemplo Northwind con permiso para realizar actualizaciones. Para obtener más información, vea Cómo: Instalar bases de datos de ejemplo.
Nota
Los cuadros de diálogo y comandos de menú que se ven pueden diferir de los descritos en la Ayuda, en función de los valores de configuración o de edición activos. Para cambiar la configuración, elija la opción Importar y exportar configuraciones del menú Herramientas. Para obtener más información, vea Customizing Development Settings in Visual Studio.
Crear un proyecto nuevo
El primer paso del tutorial es crear una nueva aplicación para Windows.
Para crear un proyecto de aplicación para Windows nuevo
Desde el menú Archivo, cree un nuevo proyecto.
Seleccione un lenguaje de programación en el panel Tipos de proyecto.
Seleccione Aplicación para Windows en el panel Plantillas.
Denomine el proyecto
ConcurrencyWalkthrough
y, a continuación, haga clic en Aceptar.Visual Studio agrega el proyecto al Explorador de soluciones y muestra un nuevo formulario en el diseñador.
Crear el conjunto de datos Northwind
En esta sección se creará un conjunto de datos denominado NorthwindDataSet
.
Para crear el conjunto de datos NorthwindDataSet
En el menú Datos, elija Agregar nuevo origen de datos.
Se abrirá el Asistente para la configuración de orígenes de datos.
Seleccione Base de datos en la página Elegir un tipo de origen de datos.
Seleccione una conexión a la base de datos de ejemplo Northwind desde la lista de conexiones disponibles o haga clic en Nueva conexión si la conexión no está disponible en la lista de conexiones.
Nota
Si intenta conectar a un archivo de la base de datos local, seleccione No cuando se le pregunte si desea agregar el archivo al proyecto.
Haga clic en Siguiente en la página Guardar la cadena de conexión en el archivo de configuración de la aplicación.
Expanda el nodo Tablas y seleccione la tabla
Customers
. El nombre predeterminado del conjunto de datos debería serNorthwindDataSet
.Haga clic en Finalizar para agregar el conjunto de datos al proyecto.
Crear un control DataGridView enlazado a datos
En esta sección se creará un control DataGridView arrastrando el elemento Customers desde la ventana Orígenes de datos hasta el Windows Form.
Para crear un control DataGridView enlazado a la tabla Customers
En el menú Datos, elija Mostrar orígenes de datos para abrir la Ventana de orígenes de datos.
En la ventana Orígenes de datos, expanda el nodo NorthwindDataSet y seleccione la tabla Customers.
Haga clic en la flecha hacia abajo del nodo de tabla y seleccione DataGridView en la lista desplegable.
Arrastre la tabla hasta un área vacía de su formulario.
Se agregan un control DataGridView llamado
CustomersDataGridView
y un control BindingNavigator denominadoCustomersBindingNavigator
al formulario enlazado con el BindingSource que, a su vez, está enlazado con la tablaCustomers
del conjunto de datosNorthwindDataSet
.
Punto de control
Ahora es posible comprobar el formulario para asegurarse de que se comporta de la forma prevista.
Para comprobar el formulario
Presione F5 para ejecutar la aplicación.
El formulario aparece con un control DataGridView que está relleno con los datos de la tabla
Customers
.En el menú Depurar, elija Detener depuración.
Controlar errores de simultaneidad
La manera de controlar errores dependerá de los fines concretos para los que diseñe la aplicación. Para este tutorial, después de que se produzca una infracción de simultaneidad, se utilizará la estrategia siguiente como ejemplo de control de errores de simultaneidad:
La aplicación presentará al usuario tres versiones del registro:
El registro actual en la base de datos.
El registro original cargado en el conjunto de datos.
Los cambios propuestos en el conjunto de datos.
Entonces, el usuario puede sobrescribir la base de datos con la versión propuesta o cancelar la actualización y actualizar el conjunto de datos con los nuevos valores de la base de datos.
Para habilitar el control de errores de simultaneidad
Crear un controlador de errores personalizado.
Presentar opciones al usuario.
Procesar la respuesta del usuario.
Reenviar la actualización o reestablecer los datos en el conjunto de datos.
Agregar Código para controlar la excepción de simultaneidad
Cuando intenta realizar una actualización pero se produce una excepción, puede utilizar la información que proporciona la excepción.
En esta sección agregará código que intentará actualizar la base de datos y controlará cualquier excepción DBConcurrencyException que se produzca, además de cualquier otra excepción.
Nota
Los métodos CreateMessage
y ProcessDialogResults
se agregarán más adelante en este tutorial.
Para agregar control de errores para el error de simultaneidad
Agregue el código siguiente al método
Form1_Load
: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
Reemplace el método
CustomersBindingNavigatorSaveItem_Click
para llamar al métodoUpdateDatabase
de manera que tenga el siguiente aspecto: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
Presentar opciones al usuario
El código que acaba de escribir llama al procedimiento CreateMessage
para mostrar información de error al usuario. En este tutorial, se usará un cuadro de mensaje para mostrar al usuario las distintas versiones del registro y permitirle elegir si desea sobrescribir el registro con los cambios o cancelar la edición. Cuando el usuario selecciona una opción (hace clic en un botón) en el cuadro de mensaje, la respuesta se pasa al método ProcessDialogResult
.
Para crear el mensaje que se mostrará al usuario
Cree el mensaje agregando el código siguiente en el Editor de código. Escriba este código debajo del método
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
Procesar la respuesta del usuario
También necesitará código para procesar la respuesta del usuario al cuadro de mensaje. Las opciones son sobrescribir el registro actual en la base de datos con el cambio propuesto o abandonar los cambios locales y actualizar la tabla de datos con el registro actual de la base de datos. Si el usuario elige sí, se llama al método Merge con el argumento preserveChanges establecido en true
. Esto hará la actualización llegue a efectuarse, ya que ahora la versión original del registro coincide con el registro de la base de datos.
Para procesar la respuesta del usuario en el cuadro de mensaje
Agregue el código siguiente debajo del código agregado en la sección anterior.
// 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
Pruebas
Puede comprobar el formulario para asegurarse de que se comporta de la forma prevista. Para simular una infracción de la simultaneidad necesita cambiar los datos en la base de datos después de rellenar el NorthwindDataSet.
Para comprobar el formulario
Presione F5 para ejecutar la aplicación.
Después de que el formulario aparezca, ejecútelo y cambie al IDE de Visual Studio.
En el menú Ver, elija Explorador de servidores.
En el Explorador de servidores, expanda la conexión que utiliza la aplicación y, a continuación, expanda el nodo Tablas.
Haga clic con el botón secundario del mouse en la tabla Customers y seleccione Mostrar datos de tabla.
En el primer registro (
ALFKI
), cambie el valor deContactName
aMaria Anders2
.Nota
Navegue hasta una fila diferente para confirmar el cambio.
Cambie al formulario en ejecución de
ConcurrencyWalkthrough
.En el primer registro del formulario (
ALFKI
), cambie el valor deContactName
aMaria Anders1
.Haga clic en el botón Guardar.
Se produce el error de simultaneidad y aparece el cuadro de mensaje.
Al hacer clic en No se cancela la actualización y se actualiza el conjunto de datos con los valores existentes en ese momento en la base de datos, mientras que al hacer clic en Sí, se escribe en la base de datos el valor propuesto.
Vea también
Tutoriales sobre datos
Enlazar controles de Windows Forms a datos en Visual Studio
Conectarse a datos en Visual Studio
Preparar la aplicación para recibir datos
Buscar datos en la aplicación
Enlazar controles a los datos en Visual Studio
Modificar datos en la aplicación
Validar datos
Guardar datos