Compartir a través de


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:

  1. Crear un proyecto nuevo de aplicación para Windows.

  2. Crear un nuevo conjunto de datos basado en la tabla Customers de Northwind.

  3. Crear un formulario con un control DataGridView para mostrar los datos.

  4. Llenar un conjunto de datos con datos de la tabla Customers de la base de datos Northwind.

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

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

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

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

  1. Desde el menú Archivo, cree un nuevo proyecto.

  2. Seleccione un lenguaje de programación en el panel Tipos de proyecto.

  3. Seleccione Aplicación para Windows en el panel Plantillas.

  4. Denomine el proyecto ConcurrencyWalkthroughy, 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

  1. En el menú Datos, elija Agregar nuevo origen de datos.

    Se abrirá el Asistente para la configuración de orígenes de datos.

  2. Seleccione Base de datos en la página Elegir un tipo de origen de datos.

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

  4. Haga clic en Siguiente en la página Guardar la cadena de conexión en el archivo de configuración de la aplicación.

  5. Expanda el nodo Tablas y seleccione la tabla Customers. El nombre predeterminado del conjunto de datos debería ser NorthwindDataSet.

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

  1. En el menú Datos, elija Mostrar orígenes de datos para abrir la Ventana de orígenes de datos.

  2. En la ventana Orígenes de datos, expanda el nodo NorthwindDataSet y seleccione la tabla Customers.

  3. Haga clic en la flecha hacia abajo del nodo de tabla y seleccione DataGridView en la lista desplegable.

  4. Arrastre la tabla hasta un área vacía de su formulario.

    Se agregan un control DataGridView llamado CustomersDataGridView y un control BindingNavigator denominado CustomersBindingNavigator al formulario enlazado con el BindingSource que, a su vez, está enlazado con la tabla Customers del conjunto de datos NorthwindDataSet.

Punto de control

Ahora es posible comprobar el formulario para asegurarse de que se comporta de la forma prevista.

Para comprobar el formulario

  1. Presione F5 para ejecutar la aplicación.

    El formulario aparece con un control DataGridView que está relleno con los datos de la tabla Customers.

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

  1. Crear un controlador de errores personalizado.

  2. Presentar opciones al usuario.

  3. Procesar la respuesta del usuario.

  4. 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
  1. 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
    
  2. Reemplace el método CustomersBindingNavigatorSaveItem_Click para llamar al método UpdateDatabase 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

  1. Presione F5 para ejecutar la aplicación.

  2. Después de que el formulario aparezca, ejecútelo y cambie al IDE de Visual Studio.

  3. En el menú Ver, elija Explorador de servidores.

  4. En el Explorador de servidores, expanda la conexión que utiliza la aplicación y, a continuación, expanda el nodo Tablas.

  5. Haga clic con el botón secundario del mouse en la tabla Customers y seleccione Mostrar datos de tabla.

  6. En el primer registro (ALFKI), cambie el valor de ContactName a Maria Anders2.

    Nota

    Navegue hasta una fila diferente para confirmar el cambio.

  7. Cambie al formulario en ejecución de ConcurrencyWalkthrough.

  8. En el primer registro del formulario (ALFKI), cambie el valor de ContactName a Maria Anders1.

  9. Haga clic en el botón Guardar.

    Se produce el error de simultaneidad y aparece el cuadro de mensaje.

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