Бөлісу құралы:


Выполнение пакетных операций с помощью DataAdapters

Поддержка пакетных операций в ADO.NET позволяет объекту DataAdapter группировать операции INSERT, UPDATE и DELETE из DataSet или DataTable к серверу вместо отправки за один раз одной операции. Уменьшение числа обращений к серверу обычно приводит к значительному улучшению производительности. Пакетные обновления поддерживаются для поставщиков .NET-данных для SQL Server (System.Data.SqlClient) и Oracle (System.Data.OracleClient).

При обновлении базы данных изменениями из объекта DataSet в более ранних версиях ADO.NET метод Update для DataAdapter выполнял обновления в базе данных по одной строке. Когда он просматривает строки в указанной таблице DataTable, он проверяет каждую строку DataRow, чтобы выявить, не была ли она изменена. Если строка изменена, он вызывает соответствующую команду UpdateCommand, InsertCommand или DeleteCommand в зависимости от значения свойства RowState для этой строки. Каждое обновление строки включало сетевой запрос к базе данных.

Начиная с ADO.NET 2.0, объект DbDataAdapter предоставляет свойство UpdateBatchSize. При установке для свойства UpdateBatchSize положительного целого значения обновления базы данных посылаются как пакеты указанного размера. Например, при установке UpdateBatchSize в 10 производится группирование 10 отдельных инструкций и передача их как один пакет. При установке UpdateBatchSize на 0 DataAdapter использует наибольший размер пакета, который может обработать сервер. Установив значение 1, отключаются пакетные обновления, так как строки отправляются по одной.

Выполнение очень больших пакетов может снизить производительность. Поэтому необходимо экспериментальным путем найти параметр оптимального размера пакета перед реализацией приложения.

Использование свойства UpdateBatchSize

Если пакетные обновления включены, значение свойства UpdatedRowSource для UpdateCommand, InsertCommand и DeleteCommand объекта DataAdapter должно быть установлено в None или OutputParameters. При выполнении пакетного обновления значение свойства UpdatedRowSource команды для FirstReturnedRecord или Both недействительно.

Следующая процедура демонстрирует использование свойства UpdateBatchSize. Процедура принимает два аргумента: объект, содержащий столбцы, которые представляют поля DataSet и ProductCategoryID в таблице Name, а также целое число, представляющее размер пакета (количество строк в пакете). Код создает новый объект SqlDataAdapter, устанавливая его свойства UpdateCommand, InsertCommand и DeleteCommand. В коде предполагается, что объект DataSet имеет измененные строки. В нем устанавливается свойство UpdateBatchSize и выполняется обновление.

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

DataAdapter имеет два события, связанные с обновлениями: RowUpdating и RowUpdated. В более ранних версиях ADO.NET, если пакетная обработка отключена, каждое из этих событий формируется для каждой обрабатываемой строки. RowUpdating создается перед обновлением и RowUpdated создается после завершения обновления базы данных.

Изменение поведения событий при пакетных обновлениях

Если пакетное обновление включено, несколько строк обновляются одной операцией базы данных. Поэтому для каждого пакета происходит только одно событие RowUpdated, в то время как событие RowUpdating происходит для каждой обрабатываемой строки. Если пакетная обработка отключена, два события инициируются по принципу чередования один к одному: одно событие RowUpdating и одно событие RowUpdated инициируются для строки, затем одно событие RowUpdating и одно событие RowUpdated инициируются для следующей строки, и так продолжается, пока не будут обработаны все строки.

Доступ к обновленным строкам

Если пакетная обработка отключена, доступ к обновляемой строке может быть выполнен при помощи свойства Row класса RowUpdatedEventArgs.

Если пакетная обработка включена для нескольких строк, формируется одно событие RowUpdated. Поэтому значение свойства Row для каждой из строк равно NULL. События RowUpdating по-прежнему генерируются для каждой строки. Метод CopyToRows класса RowUpdatedEventArgs позволяет обращаться к обработанным строкам, копируя ссылки на строки в массив. Если строки не обрабатываются, CopyToRows выбрасывает ArgumentNullException. Свойство RowCount используется для возврата числа строк, обработанных перед вызовом метода CopyToRows.

Обработка ошибок данных

Пакетное выполнение оказывает то же влияние, что и выполнение каждой отдельной инструкции. Инструкции выполняются в том порядке, в котором они были добавлены в пакет. Ошибки обрабатываются в пакетном режиме таким же образом, как и при его отключении. Каждая строка обрабатывается отдельно. Только успешно обработанные в базе данных строки будут обновлены в соответствующей строке DataRow таблицы DataTable.

Поставщик данных и сервер базы данных определяют, какие конструкции SQL поддерживаются для пакетного выполнения. Возможна генерация исключения, если подана неподдерживаемая инструкция для выполнения.

См. также