Поделиться через


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

Метод Merge можно использовать для объединения содержимого массива DataSet, DataTable или DataRow с существующим DataSet. Несколько факторов и параметров влияют на то, как новые данные объединяются с существующим DataSet.

Первичные ключи

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

Если входные или существующие строки имеют состояние Added, значения их первичных ключей согласуются с использованием значения первичного ключа Current строки Added, т. к. не существует версии строки Original.

Если входная таблица и существующая таблица содержат столбцы с одинаковым именем, но разных типов данных, возникает исключение и инициируется событие MergeFailed объекта DataSet. Если входная таблица и существующая таблица обе имеют определенные ключи, но первичные ключи относятся к разным столбцам, возникает исключение и инициируется событие MergeFailed объекта DataSet.

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

Имена таблиц и пространства имен

Объектам DataTable может быть, если необходимо, присвоено значение свойства Namespace. Когда присваиваются значения Namespace, DataSet может содержать несколько объектов DataTable с одинаковым значением TableName. Во время операции объединения и TableName, и Namespace используются для идентификации цели объединения. Если Namespace не назначено, только TableName используется для идентификации цели объединения.

ПримечаниеПримечание

Это поведение в .NET Framework версии 2.0 изменяется.В версии 1.1 пространства имен поддерживались, но во время операций объединения не учитывались.По этой причине DataSet, который использует значения свойства Namespace, будет иметь разные характеристики в зависимости от того, какая версия .NET Framework выполняется.Например, предположим, имеются два DataSets, содержащие DataTables с одинаковыми значениями свойства TableName, но с разными значениями свойства Namespace.В .NET Framework версии 1.1 разные имена Namespace пропускаются, когда объединяются два объекта DataSet.Однако, начиная с версии 2.0, слияние приводит к созданию в целевом объекте DataSet двух новых объектов DataTables.Исходные таблицы DataTables объединением не затрагиваются.

Флаг PreserveChanges

Когда DataSet, DataTable или DataRow передается в метод Merge, можно включить необязательные параметры, указывающие, сохранять ли изменения в существующем объекте DataSet и как обрабатывать элементы новой схемы в исходных данных. Первым из этих параметров после входных данных является логический флаг PreserveChanges, который задает, сохранять ли изменения в существующем DataSet. Если флаг PreserveChanges установлен в true, входные значения не переопределяют существующие значения в версии Current текущей строки. Если флаг PreserveChanges установлен в false, входные значения переопределяют существующие значения в версии Current текущей строки. Если флаг PreserveChanges не задан, по умолчанию он устанавливается в false. Дополнительные сведения о версиях строк см. в разделе Состояния и версии строк.

Если PreserveChanges имеет значение true, данные из существующей строки сохраняются в версии Current текущей строки, в то время как данные из версии Original существующей строки переопределяются данными из версии Original входной строки. RowState существующей строки установлен в Modified. Применяются следующие исключения:

  • Если существующая строка имеет версию RowState Deleted, это RowState остается Deleted и не устанавливается в Modified. В этом случае данные из входной строки будут сохраняться в версии Original существующей строки, переопределяя версию Original существующей строки (если только входная строка не имеет RowState, равное Added).

  • Если входная строка имеет состояние RowState, равное Added, данные из версии Original существующей строки не переопределяются данными из входной строки, т. к. входная строка не имеет версии Original.

Если PreserveChanges равно false, версии строк Current и Original в существующей строке переопределяются данными из входной строки, а состояние RowState существующей строки устанавливается в состояние RowState входной строки. Применяются следующие исключения:

  • Если входная строка имеет значение RowState, равное Unchanged, а существующая строка имеет значение RowState, равное Modified, Deleted или Added, состояние RowState существующей строки устанавливается в Modified.

  • Если входная строка имеет состояние RowState, равное Added, а существующая строка имеет состояние RowState, равное Unchanged, Modified или Deleted, состояние RowState существующей строки устанавливается в Modified. Также данные из версии Original существующей строки не переопределяются данными из входной строки, т. к. входная строка не имеет версии Original.

Параметр MissingSchemaAction

Можно использовать необязательный параметр MissingSchemaAction метода Merge для задания того, как Merge будет обрабатывать элементы схемы во входных данных, не являющихся частью существующего объекта DataSet.

В следующей таблице описываются параметры для MissingSchemaAction.

Параметр MissingSchemaAction

Описание

Add

Добавление новых данных схемы в объект DataSet и заполнение новых столбцов входными значениями. Это значение по умолчанию.

AddWithKey

Добавление новых данных схемы и первичного ключа в объект DataSet и заполнение новых столбцов входными значениями.

Error

Инициация исключения, если встречаются несовпадающие данные схемы.

Ignore

Пропуск новых данных схемы.

Ограничения

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

Рассмотрим случай, когда существующая строка в DataSet является строкой Unchanged со значением первичного ключа, равным 1. Во время выполнения операции слияния с входной строкой Modified со значением первичного ключа Original, равным 2, и значением первичного ключа Current, равным 1, существующая строка и входная строка не считаются совпадающими, так как различаются значения первичных ключей Original. Однако после завершения объединения и проверки ограничений появится исключение, т. к. значения первичного ключа Current нарушают ограничение уникальности для столбца первичного ключа.

ПримечаниеПримечание

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

В следующем примере кода два объекта DataSet с разными схемами объединяются в один объект DataSet с объединенными схемами двух входных объектов DataSet.

Using connection As SqlConnection = New SqlConnection( _
   connectionString)

    Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
      "SELECT CustomerID, CompanyName FROM Customers", connection)

    connection.Open()

    Dim customers As DataSet = New DataSet()
    adapter.FillSchema(customers, SchemaType.Source, "Customers")
    adapter.Fill(customers, "Customers")

    Dim orders As DataSet = New DataSet()
    orders.ReadXml("Orders.xml", XmlReadMode.ReadSchema)
    orders.AcceptChanges()

    customers.Merge(orders, True, MissingSchemaAction.AddWithKey)
End Using
using (SqlConnection connection =
           new SqlConnection(connectionString))
{
    SqlDataAdapter adapter = 
        new SqlDataAdapter(
        "SELECT CustomerID, CompanyName FROM dbo.Customers", 
        connection);

    connection.Open();

    DataSet customers = new DataSet();
    adapter.FillSchema(customers, SchemaType.Source, "Customers");
    adapter.Fill(customers, "Customers");

    DataSet orders = new DataSet();
    orders.ReadXml("Orders.xml", XmlReadMode.ReadSchema);
    orders.AcceptChanges();

    customers.Merge(orders, true, MissingSchemaAction.AddWithKey);

В следующем примере кода берется существующий объект DataSet с обновлениями и эти обновления передаются в DataAdapter, чтобы выполнить обработку в источнике данных. Затем результаты объединяются в исходный объект DataSet. После отклонения изменений, в результате которых возникла ошибка, объединенные изменения фиксируются при помощи AcceptChanges.

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

            ' Make modifications to the Customers table.

            ' Get changes to the DataSet.
            Dim dataSetChanges As DataSet = dataSet.GetChanges()

            ' Add an event handler to handle the errors during Update.
            AddHandler adapter.RowUpdated, New SqlRowUpdatedEventHandler( _
              AddressOf OnRowUpdated)

            connection.Open()
            adapter.Update(dataSetChanges, "Customers")
            connection.Close()

            ' Merge the updates.
            dataSet.Merge(dataSetChanges, True, MissingSchemaAction.Add)

            ' Reject changes on rows with errors and clear the error.
            Dim errRows() As DataRow = dataSet.Tables("Customers").GetErrors()
            Dim errRow As DataRow
            For Each errRow In errRows
                errRow.RejectChanges()
                errRow.RowError = Nothing
            Next

            ' Commit the changes.
            dataSet.AcceptChanges()

            DataTable customers = dataSet.Tables["Customers"];

            // Make modifications to the Customers table.

            // Get changes to the DataSet.
            DataSet dataSetChanges = dataSet.GetChanges();

            // Add an event handler to handle the errors during Update.
            adapter.RowUpdated += new SqlRowUpdatedEventHandler(OnRowUpdated);

            connection.Open();
            adapter.Update(dataSetChanges, "Customers");
            connection.Close();

            // Merge the updates.
            dataSet.Merge(dataSetChanges, true, MissingSchemaAction.Add);

            // Reject changes on rows with errors and clear the error.
            DataRow[] errRows = dataSet.Tables["Customers"].GetErrors();
            foreach (DataRow errRow in errRows)
            {
                errRow.RejectChanges();
                errRow.RowError = null;
            }

            // Commit the changes.
            dataSet.AcceptChanges();

Private Sub OnRowUpdated( _
    ByVal sender As Object, ByVal args As SqlRowUpdatedEventArgs)
    If args.Status = UpdateStatus.ErrorsOccurred Then
        args.Row.RowError = args.Errors.Message
        args.Status = UpdateStatus.SkipCurrentRow
    End If
End Sub
protected static void OnRowUpdated(
    object sender, SqlRowUpdatedEventArgs args)
{
    if (args.Status == UpdateStatus.ErrorsOccurred)
    {
        args.Row.RowError = args.Errors.Message;
        args.Status = UpdateStatus.SkipCurrentRow;
    }
}

См. также

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

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

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

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

Объекты DataSet, DataTable и DataView (ADO.NET)

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

Получение и изменение данных в ADO.NET