Обновление источников данных с помощью объектов DataAdapter (ADO.NET)

Обновлен: November 2007

Метод Update объекта DataAdapter вызывается для решения задачи по передаче изменений из DataSet обратно в источник данных. Метод Update, как и метод Fill, принимает в качестве аргументов экземпляр DataSet, а также (необязательно) объект DataTable или имя DataTable. Экземпляр DataSet представляет собой объект DataSet, который содержит выполненные изменения, а DataTable указывает на таблицу, из которой должны быть получены эти изменения. Если ни один объект DataTable не задан, используется первый объект DataTable в DataSet.

При вызове метода Update в DataAdapter анализируются внесенные изменения и выполняется соответствующая команда (INSERT, UPDATE или DELETE). Если в DataAdapter обнаруживается изменение в DataRow, то в этом объекте используется команда InsertCommand, UpdateCommand или DeleteCommand для обработки этого изменения. Это позволяет максимально повысить производительность приложения ADO.NET путем задания синтаксиса команды во время разработки, а также, по возможности, за счет применения хранимых процедур. Необходимо явно задавать команды перед вызовом Update. Если вызывается Update, и не существует подходящая команда для конкретного обновления (например, отсутствует DeleteCommand для удаленных строк), то активизируется исключение.

33y2221y.alert_note(ru-ru,VS.90).gifПримечание.

При использовании хранимых процедур SQL Server для изменения или удаления данных с помощью DataAdapter убедитесь, что в определении хранимой процедуры не указана инструкция SET NOCOUNT ON. В таком случае возвращается число затронутых строк, равное нулю, что DataAdapter интерпретирует как конфликт параллелизма. Это событие вызовет исключение DBConcurrencyException.

Параметры команды могут использоваться в целях указания входных и выходных значений для инструкции SQL или хранимой процедуры применительно к каждой модифицированной строке в DataSet. Дополнительные сведения см. в разделе Параметры DataAdapter (ADO.NET).

33y2221y.alert_note(ru-ru,VS.90).gifПримечание.

Важно учитывать различие между обозначением строки как удаленной в DataTable и удалением этой строки. Если вызывается метод Remove или RemoveAt, строка немедленно удаляется. Любые соответствующие строки в серверном источнике данных остаются не затронутыми, если после этого будет передано значение DataTable или DataSet в DataAdapter и вызван метод Update. Если же используется метод Delete, то строка остается в DataTable и отмечается как предназначенная для удаления. Если после этого будет передано значение DataTable или DataSet в DataAdapter и вызван метод Update, то соответствующая строка в серверном источнике данных становится удаленной.

Если значение DataTable сопоставляется или создается на основе одной таблицы базы данных, то можно воспользоваться тем, что объект DbCommandBuilder автоматически создает объекты DeleteCommand, InsertCommand и UpdateCommand для DataAdapter. Дополнительные сведения см. в разделе Создание команд с помощью построителей команд (ADO.NET).

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

Можно управлять тем, как значения, возвращенные из источника данных, сопоставляются в обратном направлении с DataTable вслед за вызовом метода Update объекта DataAdapter с использованием свойства UpdatedRowSource объекта DbCommand. Задавая значение свойства UpdatedRowSource равным одному из значений перечисления UpdateRowSource, можно управлять тем, должны ли пропускаться выходные параметры, возвращаемые командами DataAdapter, или применяться к изменившейся строке в DataSet. Можно также указать, применяется ли первая возвращенная строка (если она существует) к изменившейся строке в DataTable.

В следующей таблице приведено описание различных значений перечисления UpdateRowSource и показано, как они влияют на поведение команды, используемой в сочетании с DataAdapter.

Перечисление UpdatedRowSource

Описание

Both

И выходные параметры, и первая строка возвращенного результирующего набора могут быть сопоставлены с модифицированной строкой в DataSet.

FirstReturnedRecord

Только данные из первой строки возвращенного результирующего набора могут быть сопоставлены с модифицированной строкой в DataSet.

None

Любые выходные параметры или строки возвращенного результирующего набора пропускаются.

OutputParameters

Только выходные параметры могут быть сопоставлены с модифицированной строкой в DataSet.

Метод Update позволяет решить задачу по передаче внесенных изменений обратно в источник данных; но может оказаться так, что другие клиенты уже внесли изменения в данные источника данных с того момента, как последний раз было осуществлено заполнение DataSet. Чтобы обновить применяемый объект DataSet с использованием текущих данных, воспользуйтесь DataAdapter и методом Fill. Произойдет добавление новых строк к таблице, а обновленная информация будет включена в существующие строки. Метод Fill определяет, должна ли быть добавлена новая строка или обновлена существующая строка, путем проверки значений первичного ключа в строках объекта DataSet и в строках, возвращенных SelectCommand. Если в методе Fill обнаруживается значение первичного ключа какой-то строки в DataSet, которое совпадает со значением первичного ключа строки в результатах, возвращенных SelectCommand, то метод обновляет существующую строку на основании данных из строки, возвращенной SelectCommand, и задает значение RowState существующей строки, равное Unchanged. Если строка, возвращенная SelectCommand, имеет значение первичного ключа, не совпадающее ни с одним из значений первичного ключа в строках в DataSet, то метод Fill добавляет новую строку со значением RowState, равным Unchanged.

33y2221y.alert_note(ru-ru,VS.90).gifПримечание.

Если метод SelectCommand возвращает результаты инструкции OUTER JOIN, то DataAdapter не задает значение PrimaryKey для результирующего набора DataTable. Необходимо непосредственно определить значение PrimaryKey для обеспечения того, чтобы решение по обработке повторяющихся строк было принято правильно. Дополнительные сведения см. в разделе Определение первичных ключей (ADO.NET).

Чтобы обеспечить обработку исключений, которые могут возникнуть при вызове метода Update, можно воспользоваться событием RowUpdated для осуществления ответных действий на ошибки обновления строк по мере их возникновения (см. раздел Обработка событий DataAdapter (ADO.NET)) или задать значение DataAdapter.ContinueUpdateOnError равным true перед вызовом Update и осуществлять ответные действия на основании сведений об ошибке, хранящихся в свойстве RowError конкретной строки, после завершения обновления (см. раздел Сведения об ошибке строки).

Примечание   Вызов AcceptChanges применительно к DataSet, DataTable или DataRow приводит к тому, что все значения Original, относящиеся к DataRow, перезаписываются значениями Current, относящимися к DataRow. Если значения полей, которые идентифицируют строку как уникальную, были изменены, то после вызова AcceptChanges значения Original больше не будут соответствовать этим значениям в источнике данных. Метод AcceptChanges вызывается автоматически для каждой строки во время вызова метода Update объекта DataAdapter. Можно сохранить первоначальные значения во время вызова метода Update, для чего вначале следует задать значение свойства AcceptChangesDuringUpdate объекта DataAdapter равным false, или создать обработчик событий для события RowUpdated и задать значение Status, равное SkipCurrentRow. Дополнительные сведения см. в разделах Объединение содержимого DataSet (ADO.NET) и Обработка событий DataAdapter (ADO.NET).

Пример

В следующих примерах показано, как выполнить обновления применительно к модифицированным строкам путем явного задания значения UpdateCommand объекта DataAdapter и вызова его метода Update . Обратите внимание на то, что задан параметр, указанный в предложении WHERE инструкции UPDATE, чтобы использовалось значение Original объекта SourceColumn. Это важно, поскольку значение Current могло быть изменено, поэтому может не соответствовать этому значению в источнике данных. Значение Original представляет собой значение, которое использовалось для заполнения DataTable из источника данных.

Private Sub AdapterUpdate(ByVal connectionString As String)

    Using connection As SqlConnection = New SqlConnection( _
       connectionString)

        Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
          "SELECT CategoryID, CategoryName FROM dbo.Categories", _
          connection)

        adapter.UpdateCommand = New SqlCommand( _
          "UPDATE Categories SET CategoryName = @CategoryName " & _
           "WHERE CategoryID = @CategoryID", connection)

        adapter.UpdateCommand.Parameters.Add( _
           "@CategoryName", SqlDbType.NVarChar, 15, "CategoryName")

        Dim parameter As SqlParameter = _
           adapter.UpdateCommand.Parameters.Add( _
           "@CategoryID", SqlDbType.Int)
        parameter.SourceColumn = "CategoryID"
        parameter.SourceVersion = DataRowVersion.Original

        Dim categoryTable As New DataTable
        adapter.Fill(categoryTable)

        Dim categoryRow As DataRow = categoryTable.Rows(0)
        categoryRow("CategoryName") = "New Beverages"

        adapter.Update(categoryTable)

        Console.WriteLine("Rows after update.")
        Dim row As DataRow
        For Each row In categoryTable.Rows
            Console.WriteLine("{0}: {1}", row(0), row(1))
        Next
    End Using
End Sub
private static void AdapterUpdate(string connectionString)
{
    using (SqlConnection connection =
               new SqlConnection(connectionString))
    {
        SqlDataAdapter dataAdpater = new SqlDataAdapter(
          "SELECT CategoryID, CategoryName FROM Categories",
          connection);

        dataAdpater.UpdateCommand = new SqlCommand(
           "UPDATE Categories SET CategoryName = @CategoryName " +
           "WHERE CategoryID = @CategoryID", connection);

        dataAdpater.UpdateCommand.Parameters.Add(
           "@CategoryName", SqlDbType.NVarChar, 15, "CategoryName");

        SqlParameter parameter = dataAdpater.UpdateCommand.Parameters.Add(
          "@CategoryID", SqlDbType.Int);
        parameter.SourceColumn = "CategoryID";
        parameter.SourceVersion = DataRowVersion.Original;

        DataTable categoryTable = new DataTable();
        dataAdpater.Fill(categoryTable);

        DataRow categoryRow = categoryTable.Rows[0];
        categoryRow["CategoryName"] = "New Beverages";

        dataAdpater.Update(categoryTable);

        Console.WriteLine("Rows after update.");
        foreach (DataRow row in categoryTable.Rows)
        {
            {
                Console.WriteLine("{0}: {1}", row[0], row[1]);
            }
        }
    }
}

Столбцы AutoIncrement

Если в таблицах из применяемого источника данных имеются столбцы с автоматическим увеличением значений, то можно обеспечить заполнение столбцов в применяемом DataSet путем возврата автоматически увеличивающегося значения как выходного параметра хранимой процедуры и сопоставления его со столбцом таблицы; возврата автоматически увеличивающегося значения в первой строке результирующего набора, возвращенного хранимой процедурой или инструкцией SQL; а также использование события RowUpdated объекта DataAdapter для выполнения дополнительной инструкции SELECT. Дополнительные сведения и пример см. в разделе Извлечение значений идентификаторов или автонумерации (ADO.NET).

Упорядочение вставок, обновлений и удалений

Во многих обстоятельствах имеет значение последовательность передачи изменений, внесенных с помощью DataSet, в источник данных. Например, если происходит обновление значения первичного ключа для существующей строки и добавляется новая строка с новым значением первичного ключа в качестве внешнего ключа, то важно вначале осуществить обновление, а затем вставку.

Можно использовать метод Select объекта DataTable для возврата массива DataRow, который ссылается только на строки с конкретным значением RowState. После этого можно передать возвращенный массив DataRow в метод Update объекта DataAdapter для обработки измененных строк. Задавая подмножество строк, подлежащих обновлению, можно управлять тем, в какой последовательности обрабатываются вставки, обновления и удаления.

Пример

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

Dim table As DataTable = dataSet.Tables("Customers")

' First process deletes.
dataSet.Update(table.Select(Nothing, Nothing, _
  DataViewRowState.Deleted))

' Next process updates.
adapter.Update(table.Select(Nothing, Nothing, _
  DataViewRowState.ModifiedCurrent))

' Finally, process inserts.
dataAdpater.Update(table.Select(Nothing, Nothing, _
  DataViewRowState.Added))
DataTable table = dataSet.Tables["Customers"];

// First process deletes.
adapter.Update(table.Select(null, null, DataViewRowState.Deleted));

// Next process updates.
adapter.Update(table.Select(null, null, 
  DataViewRowState.ModifiedCurrent));

// Finally, process inserts.
adapter.Update(table.Select(null, null, DataViewRowState.Added));

См. также

Основные понятия

Состояния и версии строк

AcceptChanges и RejectChanges

Объединение содержимого DataSet (ADO.NET)

Извлечение значений идентификаторов или автонумерации (ADO.NET)

Другие ресурсы

Объекты DataAdapter и DataReader (ADO.NET)