Controlar una excepción de simultaneidadHandle a concurrency exception

Las excepciones de simultaneidad (DBConcurrencyException) se producen cuando dos usuarios intentan cambiar los mismos datos al mismo tiempo en una base de datos.Concurrency exceptions (DBConcurrencyException) are raised when two users attempt to change the same data in a database at the same time. En este tutorial, creará una aplicación de Windows que ilustra cómo detectar una DBConcurrencyException, busque la fila que produjo el error y obtenga información acerca de una estrategia para cómo controlarla.In this walkthrough, you create a Windows application that illustrates how to catch a DBConcurrencyException, locate the row that caused the error, and learn a strategy for how to handle it.

Este tutorial le guía a través del proceso siguiente:This walkthrough takes you through the following process:

  1. Cree un nuevo proyecto de aplicación de Windows Forms.Create a new Windows Forms Application project.

  2. Crear un nuevo conjunto de datos basado en la tabla Customers de Northwind.Create a new dataset based on the Northwind Customers table.

  3. Crear un formulario con un control DataGridView para mostrar los datos.Create a form with a DataGridView to display the data.

  4. Llenar un conjunto de datos con datos de la tabla Customers de la base de datos Northwind.Fill a dataset with data from the Customers table in the Northwind database.

  5. Use la mostrar datos de tabla característica de Explorador de servidores para tener acceso a la Customers datos y el cambio de un registro de la tabla.Use the Show Table Data feature in Server Explorer to access the Customers table's data and change a record.

  6. 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 produce un error de simultaneidad.Change the same record to a different value, update the dataset, and attempt to write the changes to the database, which results in a concurrency error being raised.

  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.Catch the error, then display the different versions of the record, allowing the user to determine whether to continue and update the database, or to cancel the update.

Requisitos previosPrerequisites

Este tutorial usa SQL Server Express LocalDB y la base de datos de ejemplo Northwind.This walkthrough uses SQL Server Express LocalDB and the Northwind sample database.

  1. Si no tiene SQL Server Express LocalDB, puede instalarlo desde el página de descarga de SQL Server Express, o a través del instalador de Visual Studio.If you don't have SQL Server Express LocalDB, install it either from the SQL Server Express download page, or through the Visual Studio Installer. El instalador de Visual Studio, se puede instalar SQL Server Express LocalDB como parte de la almacenamiento de datos y el procesamiento carga de trabajo, o como un componente individual.In the Visual Studio Installer, SQL Server Express LocalDB can be installed as part of the Data storage and processing workload, or as an individual component.

  2. Instalar la base de datos de ejemplo Northwind, siga estos pasos:Install the Northwind sample database by following these steps:

    1. En Visual Studio, abra el Explorador de objetos de SQL Server ventana.In Visual Studio, open the SQL Server Object Explorer window. (Explorador de objetos de SQL Server se instala como parte de la almacenamiento de datos y el procesamiento carga de trabajo en el instalador de Visual Studio.) Expanda el SQL Server nodo.(SQL Server Object Explorer is installed as part of the Data storage and processing workload in the Visual Studio Installer.) Expand the SQL Server node. Haga doble clic en la instancia de LocalDB y seleccione nueva consulta... .Right-click on your LocalDB instance and select New Query....

      Se abre una ventana del editor de consultas.A query editor window opens.

    2. Copia la script Transact-SQL de Northwind en el Portapapeles.Copy the Northwind Transact-SQL script to your clipboard. Este script de T-SQL crea la base de datos Northwind desde el principio y lo rellena con datos.This T-SQL script creates the Northwind database from scratch and populates it with data.

    3. Pegue el script de T-SQL en el editor de consultas y, a continuación, elija la Execute botón.Paste the T-SQL script into the query editor, and then choose the Execute button.

      Después de unos minutos, finaliza la ejecución de la consulta y se crea la base de datos Northwind.After a short time, the query finishes executing and the Northwind database is created.

Nota

Los cuadros de diálogo y comandos de menú que se ven pueden diferir de los descritos en la Ayuda, dependiendo de la configuración activa o la edición que esté usando.The dialog boxes and menu commands you see might differ from those described in Help depending on your active settings or the edition that you're using. Para cambiar la configuración, elija la opción Importar y exportar configuraciones del menú Herramientas .To change your settings, choose Import and Export Settings on the Tools menu. Para más información, vea Personalizar el IDE de Visual Studio.For more information, see Personalize the Visual Studio IDE.

Crear un proyecto nuevoCreate a new project

Iniciar el tutorial creando una nueva aplicación de Windows Forms.You begin your walkthrough by creating a new Windows Forms application.

Para crear un nuevo proyecto de aplicación de Windows FormsTo create a new Windows Forms application project

  1. En Visual Studio, en el archivo menú, seleccione New, proyecto... .In Visual Studio, on the File menu, select New, Project....

  2. Expanda Visual C# o Visual Basic en el panel izquierdo, seleccione escritorio clásico de Windows.Expand either Visual C# or Visual Basic in the left-hand pane, then select Windows Classic Desktop.

  3. En el panel central, seleccione la aplicación de Windows Forms tipo de proyecto.In the middle pane, select the Windows Forms App project type.

  4. Denomine el proyecto ConcurrencyWalkthroughy, a continuación, elija Aceptar.Name the project ConcurrencyWalkthrough, and then choose OK.

    El ConcurrencyWalkthrough se crea y se agrega al proyecto el Explorador de soluciones, y abre un nuevo formulario en el diseñador.The ConcurrencyWalkthrough project is created and added to Solution Explorer, and a new form opens in the designer.

Crear el conjunto de datos NorthwindCreate the Northwind dataset

En esta sección, creará un conjunto de datos denominado NorthwindDataSet.In this section, you create a dataset named NorthwindDataSet.

Para crear el conjunto de datos NorthwindDataSetTo create the NorthwindDataSet

  1. En el datos menú, elija Agregar nuevo origen de datos.On the Data menu, choose Add New Data source.

    El Asistente para configuración de orígenes de datos se abre.The Data Source Configuration Wizard opens.

  2. En el elegir un tipo de origen de datos pantalla, seleccione base de datos.On the Choose a Data Source Type screen, select Database.

  3. Seleccione una conexión a la base de datos de ejemplo Northwind desde la lista de conexiones disponibles.Select a connection to the Northwind sample database from the list of available connections. Si la conexión no está disponible en la lista de conexiones, seleccione nueva conexiónIf the connection is not available in the list of connections, select New Connection

    Nota

    Si se conecta a un archivo de base de datos local, seleccione n cuando se le pregunte si prefiere que desea agregar el archivo al proyecto.If you are connecting to a local database file, select No when asked if you would you like to add the file to your project.

  4. En el Guardar cadena de conexión en el archivo de configuración de aplicación pantalla, seleccione siguiente.On the Save connection string to the application configuration file screen, select Next.

  5. Expanda el tablas nodo y seleccione el Customers tabla.Expand the Tables node and select the Customers table. El nombre predeterminado del conjunto de datos debería ser NorthwindDataSet.The default name for the dataset should be NorthwindDataSet.

  6. Seleccione finalizar para agregar el conjunto de datos al proyecto.Select Finish to add the dataset to the project.

Crear un control DataGridView enlazado a datosCreate a data-bound DataGridView control

En esta sección, creará un DataGridView arrastrando el clientes de elementos de la orígenes de datos ventana hasta los formularios Windows Forms.In this section, you create a DataGridView by dragging the Customers item from the Data Sources window onto your Windows Form.

Para crear un control DataGridView enlazado a la tabla CustomersTo create a DataGridView control that is bound to the Customers table

  1. En el datos menú, elija Mostrar orígenes de datos para abrir el ventana Orígenes de datos.On the Data menu, choose Show Data Sources to open the Data Sources Window.

  2. En el orígenes de datos ventana, expanda la NorthwindDataSet nodo y, a continuación, seleccione la clientes tabla.In the Data Sources window, expand the NorthwindDataSet node, and then select the Customers table.

  3. Seleccione la flecha hacia abajo en el nodo de tabla y, a continuación, seleccione DataGridView en la lista desplegable.Select the down arrow on the table node, and then select DataGridView in the drop-down list.

  4. Arrastre la tabla hasta un área vacía de su formulario.Drag the table onto an empty area of your form.

    A DataGridView control denominado CustomersDataGridView y un BindingNavigator denominado CustomersBindingNavigator se agregan al formulario que está enlazado a la BindingSource. Esto es, a su vez depende de la Customers tabla el NorthwindDataSet.A DataGridView control named CustomersDataGridView and a BindingNavigator named CustomersBindingNavigator are added to the form that's bound to the BindingSource.This, is in, is turn bound to the Customers table in the NorthwindDataSet.

Comprobar el formularioTest the form

Ahora es posible comprobar el formulario para asegurarse de que se comporta de la forma prevista.You can now test the form to make sure it behaves as expected up to this point.

Para comprobar el formularioTo test the form

  1. Seleccione F5 para ejecutar la aplicaciónSelect F5 to run the application

    El formulario aparece con un DataGridView control en el mismo que se rellena con datos de la Customers tabla.The form appears with a DataGridView control on it that's filled with data from the Customers table.

  2. En el depurar menú, seleccione Detener depuración.On the Debug menu, select Stop Debugging.

Controlar los errores de simultaneidadHandle concurrency errors

Cómo controlar errores depende de las reglas de negocios específicas que rigen la aplicación.How you handle errors depends on the specific business rules that govern your application. En este tutorial, usamos la estrategia siguiente como ejemplo de cómo controlar el error de simultaneidad.For this walkthrough, we use the following strategy as an example for how to handle the concurrency error.

La aplicación presenta al usuario tres versiones del registro:The application presents the user with three versions of the record:

  • El registro actual en la base de datosThe current record in the database

  • El registro original que se carga en el conjunto de datosThe original record that's loaded into the dataset

  • Los cambios propuestos en el conjunto de datosThe proposed changes in the dataset

El usuario es capaz de 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.The user is then able to either overwrite the database with the proposed version, or cancel the update and refresh the dataset with the new values from the database.

Para habilitar el control de errores de simultaneidadTo enable the handling of concurrency errors

  1. Crear un controlador de errores personalizado.Create a custom error handler.

  2. Presentar opciones al usuario.Display choices to the user.

  3. Procesar la respuesta del usuario.Process the user's response.

  4. Reenviar la actualización o reestablecer los datos en el conjunto de datos.Resend the update, or reset the data in the dataset.

Agregue código para controlar la excepción de simultaneidadAdd code to handle the concurrency exception

Cuando se intenta realizar una actualización pero se produce una excepción, por lo general desea hacer algo con la información proporcionada por la excepción.When you attempt to perform an update and an exception gets raised, you generally want to do something with the information that's provided by the raised exception.

En esta sección, agregará código que intenta actualizar la base de datos.In this section, you add code that attempts to update the database. El usuario controle también cualquier DBConcurrencyException que se produzca, además de cualquier otra excepción.You also handle any DBConcurrencyException that might get raised, as well as any other exceptions.

Nota

Los métodos CreateMessage y ProcessDialogResults se agregarán más adelante en este tutorial.The CreateMessage and ProcessDialogResults methods will be added later in this walkthrough.

Para agregar control de errores para el error de simultaneidadTo add error handling for the concurrency error
  1. Agregue el código siguiente al método Form1_Load:Add the following code below the Form1_Load method:

    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:Replace the CustomersBindingNavigatorSaveItem_Click method to call the UpdateDatabase method so it looks like the following:

    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
    

Opciones de presentación para el usuarioDisplay choices to the user

El código que acaba de escribir llama al procedimiento CreateMessage para mostrar información de error al usuario.The code you just wrote calls the CreateMessage procedure to display error information to the user. En este tutorial, usa un cuadro de mensaje para mostrar las distintas versiones del registro para el usuario.For this walkthrough, you use a message box to display the different versions of the record to the user. Esto permite al usuario elegir si desea sobrescribir el registro con los cambios o cancelar la edición.This enables the user to choose whether to overwrite the record with the changes or cancel the edit. 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.Once the user selects an option (clicks a button) on the message box, the response is passed to the ProcessDialogResult method.

Para crear el mensaje que se mostrará al usuarioTo create the message to display to the user
  • Cree el mensaje agregando el código siguiente a la Editor de código.Create the message by adding the following code to the Code Editor. Escriba este código debajo del método UpdateDatabase.Enter this code below the UpdateDatabase method.

    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 usuarioProcess the user's response

También se necesita código para procesar la respuesta del usuario en el cuadro de mensajes.You also need code to process the user's response to the message box. 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 que está actualmente en la base de datos.The options are either to overwrite the current record in the database with the proposed change, or abandon the local changes and refresh the data table with the record that's currently in the database. Si el usuario elige Sí, el Merge método se llama con la preserveChanges establecido en true.If the user chooses yes, the Merge method is called with the preserveChanges argument set to true. Esto hace que el intento de actualización se realice correctamente, dado que la versión original del registro ahora coincide con el registro en la base de datos.This causes the update attempt to be successful, because the original version of the record now matches the record in the database.

Para procesar la respuesta del usuario en el cuadro de mensajeTo process the user input from the message box
  • Agregue el código siguiente debajo del código que agregó en la sección anterior.Add the following code below the code that was added in the previous section.

    // 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
    

Comprobar el formularioTest the form

Puede comprobar el formulario para asegurarse de que se comporta de la forma prevista.You can now test the form to make sure it behaves as expected. Para simular una infracción de la simultaneidad necesita cambiar los datos en la base de datos después de rellenar el NorthwindDataSet.To simulate a concurrency violation you need to change data in the database after filling the NorthwindDataSet.

Para comprobar el formularioTo test the form

  1. Seleccione F5 para ejecutar la aplicación.Select F5 to run the application.

  2. Después de que el formulario aparezca, ejecútelo y cambie al IDE de Visual Studio.After the form appears, leave it running and switch to the Visual Studio IDE.

  3. En el vista menú, elija Explorador de servidores.On the View menu, choose Server Explorer.

  4. En Explorador de servidores, expanda la conexión de la aplicación está utilizando y, a continuación, expanda el tablas nodo.In Server Explorer, expand the connection your application is using, and then expand the Tables node.

  5. Haga clic en el clientes de tabla y, a continuación, seleccione mostrar datos de tabla.Right-click the Customers table, and then select Show Table Data.

  6. En el primer registro (ALFKI) cambiar ContactName a Maria Anders2.In the first record (ALFKI) change ContactName to Maria Anders2.

    Nota

    Navegue hasta una fila diferente para confirmar el cambio.Navigate to a different row to commit the change.

  7. Cambie al formulario en ejecución de ConcurrencyWalkthrough.Switch to the ConcurrencyWalkthrough's running form.

  8. En el primer registro en el formulario (ALFKI), cambiarContactName a Maria Anders1.In the first record on the form (ALFKI), changeContactName to Maria Anders1.

  9. Seleccione el guardar botón.Select the Save button.

    Se produce el error de simultaneidad y aparece el cuadro de mensaje.The concurrency error is raised, and the message box appears.

  10. Seleccionar n cancela la actualización y actualiza el conjunto de datos con los valores que se encuentran actualmente en la base de datos.Selecting No cancels the update and updates the dataset with the values that are currently in the database. Seleccionar escribe el valor propuesto para la base de datos.Selecting Yes writes the proposed value to the database.

Vea tambiénSee Also

Guardar los datos de nuevo en la base de datosSave data back to the database