Tutorial: Controlar una excepción simultánea

Actualización: noviembre 2007

Las excepciones de concurrencia (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 concurrencia.

  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 poder completar este tutorial, necesitará:

Nota:

Los cuadros de diálogo y comandos de menú que se ven podrían ser distintos de los que se describen en la Ayuda, dependiendo de la configuración o edición activas. Para cambiar la configuración, elija Importar y exportar configuraciones en el menú Herramientas. Para obtener más información, vea Valores de configuración de 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 formulario Windows Forms.

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 concurrencia

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 concurrencia, se utilizará la estrategia siguiente como ejemplo de control de errores de concurrencia:

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 concurrencia

  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 concurrencia

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 concurrencia

  1. Agregue el código siguiente al método Form1_Load:

    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
    
    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.");
        }
    }
    
  2. Reemplace el método CustomersBindingNavigatorSaveItem_Click para llamar al método UpdateDatabase de manera que tenga el siguiente aspecto:

    Private Sub CustomersBindingNavigatorSaveItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CustomersBindingNavigatorSaveItem.Click
        UpdateDatabase()
    End Sub
    
    private void customersBindingNavigatorSaveItem_Click(object sender, EventArgs e)
    {
        UpdateDatabase();
    }
    

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 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
    
    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.Item(i, RowVersion).ToString() + " ";
        }
        return rowData;
    }
    

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 conjunto de argumento establecido preserveChanges en true. Esto hará que el intento de actualización sea satisfactorio, ya que ahora la versión original del registro coincide con el 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 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
    
    // 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:
                UpdateDatabase();
                break;
    
            case DialogResult.No:
                northwindDataSet.Merge(tempCustomersDataTable);
                MessageBox.Show("Update cancelled");
                break;
        }
    }
    

Pruebas

Puede comprobar el formulario para asegurarse de que se comporta de la forma prevista. Para simular una infracción de la concurrencia 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 concurrencia 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 Sí, se escribe en la base de datos el valor propuesto.

Vea también

Conceptos

Lo nuevo en datos

Información general sobre la presentación de datos

Otros recursos

Tutoriales sobre datos

Conectarse a datos en Visual Studio

Preparar la aplicación para recibir datos

Buscar datos en la aplicación

Mostrar datos en formularios en aplicaciones para Windows

Modificar datos en la aplicación

Validar datos

Guardar datos