Compartir vía


Control de una excepción de simultaneidad en aplicaciones de base de datos de .NET Framework

Nota:

Los conjuntos de datos y las clases relacionadas son tecnologías heredadas de .NET Framework de principios de la década de 2000 que permiten a las aplicaciones trabajar con datos en memoria mientras están desconectadas de la base de datos. Las tecnologías son especialmente útiles para las aplicaciones que permiten a los usuarios modificar los datos y conservar los cambios en la base de datos. Aunque los conjuntos de datos han demostrado ser una tecnología de gran éxito, se recomienda que las nuevas aplicaciones de .NET usen Entity Framework Core. Entity Framework proporciona una manera más natural de trabajar con datos tabulares como modelos de objetos y tiene una interfaz de programación más sencilla.

Las excepciones de simultaneidad (System.Data.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 de Windows que ilustra cómo detectar DBConcurrencyException, localizar la fila que provocó el error y aprender una estrategia para controlarlo.

Este tutorial le guía a través del proceso siguiente:

  1. Cree un proyecto de Aplicación de Windows Forms (.NET Framework).

  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. Use la característica Mostrar datos de tabla en el Explorador de servidores para acceder a los datos de la tabla Customers y cambiar un registro.

  6. Cambie el mismo registro a un valor diferente, actualice el conjunto de datos e intente 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

En este tutorial se usa LocalDB de SQL Server Express y la base de datos de ejemplo Northwind.

  1. Si no tiene LocalDB de SQL Server Express, instálelo desde la página de descarga de SQL Server Express, o bien mediante el Instalador de Visual Studio. En el Instalador de Visual Studio, puede instalar LocalDB de SQL Server Express como parte de la carga de trabajo Almacenamiento y procesamiento de datos, o bien como un componente individual.

  2. Siga estos pasos para instalar la base de datos de ejemplo Northwind:

    1. En Visual Studio, abra la ventana Explorador de objetos de SQL Server (Explorador de objetos de SQL Server se instala como parte de la carga de trabajo Almacenamiento y procesamiento de datos en el Instalador de Visual Studio). Expanda el nodo SQL Server. Haga clic con el botón derecho en la instancia de LocalDB y seleccione Nueva consulta.

      Se abre una ventana del editor de consultas.

    2. Copie el script de Transact-SQL Northwind en el Portapapeles. Este script de T-SQL crea la base de datos Northwind desde cero y la rellena con datos.

    3. Pegue el script de T-SQL en el editor de consultas y, después, elija el botón Ejecutar.

      Después de un breve tiempo, la consulta termina de ejecutarse y se crea la base de datos Northwind.

Creación de un nuevo proyecto

Crear un proyecto nuevo de aplicación de Windows Forms:

  1. En Visual Studio, en el menú Archivo, seleccione Nuevo>Proyecto.

  2. Expanda Visual C# o Visual Basic en el panel de la izquierda y, a continuación, seleccione Escritorio de Windows.

  3. En el panel central, seleccione el tipo de proyecto Aplicación de Windows Forms.

  4. Denomine el proyecto ConcurrencyWalkthroughy y, a continuación, haga clic en Aceptar.

    El proyecto ConcurrencyWalkthrough se crea y agrega al Explorador de soluciones y se abre un nuevo formulario en el diseñador.

Crear el conjunto de datos Northwind

A continuación, cree un conjunto de datos denominado NorthwindDataSet:

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

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

  2. En la pantalla Elegir un tipo de origen de datos, seleccione Base de datos.

    Asistente para configuración de orígenes de datos en Visual Studio

  3. Seleccione una conexión a la base de datos de ejemplo Northwind en la lista de conexiones disponibles. Si la conexión no está disponible en la lista de conexiones, seleccione Nueva conexión.

    Nota

    Si está conectándose a un archivo de la base de datos local, seleccione No cuando se le pregunte si desea agregar el archivo al proyecto.

  4. En la pantalla Guardar la cadena de conexión en el archivo de configuración de la aplicación, seleccione Siguiente.

  5. Expanda el nodo Tablas y seleccione la tabla Clientes. 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 System.Windows.Forms.DataGridView arrastrando el elemento Customers desde la ventana Orígenes de datos hasta el formulario de Windows.

  1. Para abrir la ventana Orígenes de datos, seleccione Mostrar orígenes de datos en el menú 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.

    Un control DataGridView denominado CustomersDataGridView, y un BindingNavigator denominado CustomersBindingNavigator, se agregan al formulario enlazado a BindingSource. Esto, a su vez, se enlaza a la tabla Customers en NorthwindDataSet.

Probar el formulario

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

  1. Seleccione 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, seleccione Detener depuración.

Controlar errores de la simultaneidad

La manera de controlar errores dependerá de los fines concretos para los que diseñe la aplicación. Para este tutorial, usamos la siguiente estrategia como ejemplo para controlar el error de simultaneidad.

La aplicación presenta 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 intenta actualizar la base de datos. También puede controlar cualquier DBConcurrencyException que se pueda generar, así como cualquier otra excepción.

Nota

Los métodos CreateMessage y ProcessDialogResults se agregarán más adelante en este tutorial.

  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.");
        }
    }
    

  1. 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();
    }
    

Presentar opciones al usuario

El código que acaba de escribir llama al procedimiento CreateMessage para mostrar información de error al usuario. Para este tutorial, se usa un cuadro de mensaje para mostrar las distintas versiones del registro al usuario. Esto permite al usuario 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.

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;
}

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 , se llama al método Merge con el argumento preserveChanges establecido entrue. Esto hace que la actualización llegue a efectuarse, ya que ahora la versión original del registro coincide con el registro de la base de datos.

Agregue el siguiente código 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;
    }
}

Prueba del comportamiento del formulario

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.

  1. Seleccione 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 derecho en la tabla Customers y seleccione Mostrar datos de tabla.

  6. En el primer registro (ALFKI), cambie 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 (ALFKI), cambie ContactName a Maria Anders1.

  9. Seleccione el botón Guardar.

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

    Al seleccionar No, la actualización se cancela y se actualiza el conjunto de datos con los valores que se encuentran actualmente en la base de datos. Al seleccionar , se escribe el valor propuesto en la base de datos.