Partilhar via


Executando operações em lote usando DataAdapters

O suporte em lote no ADO.NET permite agrupar DataAdapter operações INSERT, UPDATE e DELETE de um DataSet ou DataTable para o servidor, em vez de enviar uma operação de cada vez. A redução no número de viagens de ida e volta para o servidor normalmente resulta em ganhos de desempenho significativos. Há suporte para atualizações em lote para os provedores de dados .NET para SQL Server (System.Data.SqlClient) e Oracle (System.Data.OracleClient).

Ao atualizar um banco de dados com alterações de um DataSet em versões anteriores do ADO.NET, o Update método de um DataAdapter executado atualiza o banco de dados uma linha de cada vez. À medida que iterava através das linhas no especificado DataTable, examinou cada uma DataRow delas para ver se tinha sido modificada. Se a linha tivesse sido modificada, ela chamava o apropriado UpdateCommand, , ou DeleteCommand, dependendo do valor da RowState propriedade InsertCommandpara essa linha. Cada atualização de linha envolvia uma viagem de ida e volta da rede para o banco de dados.

A partir do ADO.NET 2.0, o DbDataAdapter expõe uma UpdateBatchSize propriedade. Definir o UpdateBatchSize como um valor inteiro positivo faz com que as atualizações para o banco de dados sejam enviadas como lotes do tamanho especificado. Por exemplo, definir como UpdateBatchSize 10 agrupará 10 instruções separadas e enviá-las-á como lote único. Definir como UpdateBatchSize 0 fará com que o DataAdapter use o maior tamanho de lote que o servidor pode manipular. Defini-lo como 1 desativa as atualizações em lote, pois as linhas são enviadas uma de cada vez.

A execução de um lote extremamente grande pode diminuir o desempenho. Portanto, você deve testar a configuração de tamanho de lote ideal antes de implementar seu aplicativo.

Usando a propriedade UpdateBatchSize

Quando as atualizações em lote estão habilitadas, o UpdatedRowSource valor da propriedade do DataAdapter's UpdateCommand, InsertCommande DeleteCommand deve ser definido como None ou OutputParameters. Ao executar uma atualização em lote, o valor da propriedade do comando UpdatedRowSource é Both inválidoFirstReturnedRecord.

O procedimento a seguir demonstra o uso da UpdateBatchSize propriedade. O procedimento usa dois argumentos, um DataSet objeto que tem colunas que representam os campos ProductCategoryID e Name na tabela Production.ProductCategory e um inteiro que representa o tamanho do lote (o número de linhas no lote). O código cria um novo SqlDataAdapter objeto, definindo suas UpdateCommandpropriedades , InsertCommande DeleteCommand . O código pressupõe que o DataSet objeto modificou linhas. Ele define a UpdateBatchSize propriedade e executa a atualização.

Public Sub BatchUpdate( _  
  ByVal dataTable As DataTable, ByVal batchSize As Int32)  
    ' Assumes GetConnectionString() returns a valid connection string.  
    Dim connectionString As String = GetConnectionString()  
  
    ' Connect to the AdventureWorks database.  
    Using connection As New SqlConnection(connectionString)  
        ' Create a SqlDataAdapter.  
        Dim adapter As New SqlDataAdapter()  
  
        'Set the UPDATE command and parameters.  
        adapter.UpdateCommand = New SqlCommand( _  
          "UPDATE Production.ProductCategory SET " _  
          & "Name=@Name WHERE ProductCategoryID=@ProdCatID;", _  
          connection)  
        adapter.UpdateCommand.Parameters.Add("@Name", _  
          SqlDbType.NVarChar, 50, "Name")  
        adapter.UpdateCommand.Parameters.Add("@ProdCatID",  _  
          SqlDbType.Int, 4, " ProductCategoryID ")  
        adapter.UpdateCommand.UpdatedRowSource = _  
          UpdateRowSource.None  
  
        'Set the INSERT command and parameter.  
        adapter.InsertCommand = New SqlCommand( _  
          "INSERT INTO Production.ProductCategory (Name) VALUES (@Name);", _  
  connection)  
        adapter.InsertCommand.Parameters.Add("@Name", _  
          SqlDbType.NVarChar, 50, "Name")  
        adapter.InsertCommand.UpdatedRowSource = _  
          UpdateRowSource.None  
  
        'Set the DELETE command and parameter.  
        adapter.DeleteCommand = New SqlCommand( _  
          "DELETE FROM Production.ProductCategory " _  
          & "WHERE ProductCategoryID=@ProdCatID;", connection)  
        adapter.DeleteCommand.Parameters.Add("@ProdCatID", _  
           SqlDbType.Int, 4, " ProductCategoryID ")  
        adapter.DeleteCommand.UpdatedRowSource = UpdateRowSource.None  
  
        ' Set the batch size.  
        adapter.UpdateBatchSize = batchSize  
  
        ' Execute the update.  
        adapter.Update(dataTable)  
    End Using  
End Sub  
public static void BatchUpdate(DataTable dataTable,Int32 batchSize)  
{  
    // Assumes GetConnectionString() returns a valid connection string.  
    string connectionString = GetConnectionString();  
  
    // Connect to the AdventureWorks database.  
    using (SqlConnection connection = new
      SqlConnection(connectionString))  
    {  
  
        // Create a SqlDataAdapter.  
        SqlDataAdapter adapter = new SqlDataAdapter();  
  
        // Set the UPDATE command and parameters.  
        adapter.UpdateCommand = new SqlCommand(  
            "UPDATE Production.ProductCategory SET "  
            + "Name=@Name WHERE ProductCategoryID=@ProdCatID;",
            connection);  
        adapter.UpdateCommand.Parameters.Add("@Name",
           SqlDbType.NVarChar, 50, "Name");  
        adapter.UpdateCommand.Parameters.Add("@ProdCatID",
           SqlDbType.Int, 4, "ProductCategoryID");  
         adapter.UpdateCommand.UpdatedRowSource = UpdateRowSource.None;  
  
        // Set the INSERT command and parameter.  
        adapter.InsertCommand = new SqlCommand(  
            "INSERT INTO Production.ProductCategory (Name) VALUES (@Name);",
            connection);  
        adapter.InsertCommand.Parameters.Add("@Name",
          SqlDbType.NVarChar, 50, "Name");  
        adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.None;  
  
        // Set the DELETE command and parameter.  
        adapter.DeleteCommand = new SqlCommand(  
            "DELETE FROM Production.ProductCategory "  
            + "WHERE ProductCategoryID=@ProdCatID;", connection);  
        adapter.DeleteCommand.Parameters.Add("@ProdCatID",
          SqlDbType.Int, 4, "ProductCategoryID");  
        adapter.DeleteCommand.UpdatedRowSource = UpdateRowSource.None;  
  
        // Set the batch size.  
        adapter.UpdateBatchSize = batchSize;  
  
        // Execute the update.  
        adapter.Update(dataTable);  
    }  
}  

O DataAdapter tem dois eventos relacionados à atualização: RowUpdating e RowUpdated. Em versões anteriores do ADO.NET, quando o processamento em lote é desativado, cada um desses eventos é gerado uma vez para cada linha processada. RowUpdating é gerado antes da atualização ocorrer e RowUpdated é gerado após a conclusão da atualização do banco de dados.

Alterações no comportamento do evento com atualizações em lote

Quando o processamento em lote está habilitado, várias linhas são atualizadas em uma única operação de banco de dados. Portanto, apenas um RowUpdated evento ocorre para cada lote, enquanto o RowUpdating evento ocorre para cada linha processada. Quando o processamento em lote é desativado, os dois eventos são acionados com intercalação um-para-um, onde um RowUpdating evento e um RowUpdated evento são acionados para uma linha e, em seguida, um RowUpdating e um RowUpdated evento são acionados para a próxima linha, até que todas as linhas sejam processadas.

Acessando linhas atualizadas

Quando o processamento em lote está desabilitado, a linha que está sendo atualizada pode ser acessada usando a RowRowUpdatedEventArgs propriedade da classe.

Quando o processamento em lote está habilitado, um único RowUpdated evento é gerado para várias linhas. Portanto, o Row valor da propriedade para cada linha é null. RowUpdating Os eventos ainda são gerados para cada linha. O CopyToRows método da RowUpdatedEventArgs classe permite que você acesse as linhas processadas copiando referências às linhas em uma matriz. Se nenhuma linha estiver sendo processada, CopyToRows lançará um ArgumentNullExceptionarquivo . Use a RowCount propriedade para retornar o número de linhas processadas antes de chamar o CopyToRows método.

Tratamento de erros de dados

A execução em lote tem o mesmo efeito que a execução de cada instrução individual. As instruções são executadas na ordem em que foram adicionadas ao lote. Os erros são tratados da mesma forma no modo de lote como quando o modo de lote está desativado. Cada linha é processada separadamente. Somente as linhas que foram processadas com êxito no banco de dados serão atualizadas no correspondente DataRow dentro do DataTable.

O provedor de dados e o servidor de banco de dados back-end determinam quais construções SQL têm suporte para execução em lote. Uma exceção pode ser lançada se uma instrução sem suporte for enviada para execução.

Consulte também