Слияние содержимого набора данныхMerging DataSet Contents

Метод Merge можно использовать для объединения содержимого массива DataSet, DataTable или DataRow с существующим DataSet.You can use the Merge method to merge the contents of a DataSet, DataTable, or DataRow array into an existing DataSet. Несколько факторов и параметров влияют на то, как новые данные объединяются с существующим DataSet.Several factors and options affect how new data is merged into an existing DataSet.

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

Если таблица, получающая в результате слияния новые данные и схему, имеет первичный ключ, новые строки входных данных сравниваются с существующими строками, имеющими такие же значения первичного ключа Original, что и во входных данных.If the table receiving new data and schema from a merge has a primary key, new rows from the incoming data are matched with existing rows that have the same Original primary key values as those in the incoming data. Если столбцы из входной схемы соответствуют столбцам существующей схемы, данные в существующих строках изменяются.If the columns from the incoming schema match those of the existing schema, the data in the existing rows is modified. Столбцы, не соответствующие существующей схеме, либо пропускаются, либо добавляются на основании параметра MissingSchemaAction.Columns that do not match the existing schema are either ignored or added based on the MissingSchemaAction parameter. Новые строки со значениями первичного ключа, которые не соответствуют существующим строкам, добавляются к существующей таблице.New rows with primary key values that do not match any existing rows are appended to the existing table.

Если входные или существующие строки имеют состояние Added, значения их первичных ключей согласуются с использованием значения первичного ключа Current строки Added, т. к. не существует версии строки Original.If incoming or existing rows have a row state of Added, their primary key values are matched using the Current primary key value of the Added row because no Original row version exists.

Если входная таблица и существующая таблица содержат столбцы с одинаковым именем, но разных типов данных, возникает исключение и инициируется событие MergeFailed объекта DataSet.If an incoming table and an existing table contain a column with the same name but different data types, an exception is thrown and the MergeFailed event of the DataSet is raised. Если входная таблица и существующая таблица обе имеют определенные ключи, но первичные ключи относятся к разным столбцам, возникает исключение и инициируется событие MergeFailed объекта DataSet.If an incoming table and an existing table both have defined keys, but the primary keys are for different columns, an exception is thrown and the MergeFailed event of the DataSet is raised.

Если таблица, получающая новые данные в результате объединения, не имеет первичного ключа, новые строки входных данных не могут быть сопоставлены существующим строкам в таблице и вместо этого присоединяются к существующей таблице.If the table receiving new data from a merge does not have a primary key, new rows from the incoming data cannot be matched to existing rows in the table and are instead appended to the existing table.

Имена таблиц и пространства именTable Names and Namespaces

Объектам DataTable может быть, если необходимо, присвоено значение свойства Namespace.DataTable objects can optionally be assigned a Namespace property value. Когда присваиваются значения Namespace, DataSet может содержать несколько объектов DataTable с одинаковым значением TableName.When Namespace values are assigned, a DataSet can contain multiple DataTable objects with the same TableName value. Во время операции слияния и TableName, и Namespace используются для идентификации цели слияния.During merge operations, both TableName and Namespace are used to identify the target of a merge. Если Namespace не назначено, только TableName используется для идентификации цели слияния.If no Namespace has been assigned, only the TableName is used to identify the target of a merge.

Примечание

Это поведение в .NET Framework версии 2.0 изменяется.This behavior changed in version 2.0 of the .NET Framework. В версии 1.1 пространства имен поддерживались, но во время операций слияния не учитывались.In version 1.1, namespaces were supported but were ignored during merge operations. По этой причине DataSet, который использует значения свойства Namespace, будет иметь разные характеристики в зависимости от того, какая версия .NET Framework выполняется.For this reason, a DataSet that uses Namespace property values will have different behaviors depending on which version of the .NET Framework you are running. Например, предположим, имеются два DataSets, содержащие DataTables с одинаковыми значениями свойства TableName, но с разными значениями свойства Namespace.For example, suppose you have two DataSets containing DataTables with the same TableName property values but different Namespace property values. В .NET Framework версии 1.1 разные имена Namespace пропускаются, когда объединяются два объекта DataSet.In version 1.1 of the .NET Framework, the different Namespace names will be ignored when merging the two DataSet objects. Однако, начиная с версии 2.0, слияние приводит к созданию в целевом объекте DataTables двух новых объектов DataSet.However, starting with version 2.0, merging causes two new DataTables to be created in the target DataSet. Исходные таблицы DataTables объединением не затрагиваются.The original DataTables will be unaffected by the merge.

Флаг PreserveChangesPreserveChanges

Когда DataSet, DataTable или DataRow передается в метод Merge, можно включить необязательные параметры, указывающие, сохранять ли изменения в существующем объекте DataSet и как обрабатывать элементы новой схемы в исходных данных.When you pass a DataSet, DataTable, or DataRow array to the Merge method, you can include optional parameters that specify whether or not to preserve changes in the existing DataSet, and how to handle new schema elements found in the incoming data. Первым из этих параметров после входных данных является логический флаг PreserveChanges, который задает, сохранять ли изменения в существующем DataSet.The first of these parameters after the incoming data is a Boolean flag, PreserveChanges, which specifies whether or not to preserve the changes in the existing DataSet. Если флаг PreserveChanges установлен в true, входные значения не переопределяют существующие значения в версии Current текущей строки.If the PreserveChanges flag is set to true, incoming values do not overwrite existing values in the Current row version of the existing row. Если флаг PreserveChanges установлен в false, входные значения переопределяют существующие значения в версии Current текущей строки.If the PreserveChanges flag is set to false, incoming values do overwrite the existing values in the Current row version of the existing row. Если флаг PreserveChanges не задан, по умолчанию он устанавливается в false.If the PreserveChanges flag is not specified, it is set to false by default. Дополнительные сведения о версиях строк см. в разделе состояния строк и версии строк.For more information about row versions, see Row States and Row Versions.

Если PreserveChanges имеет значение true, данные из существующей строки сохраняются в версии Current текущей строки, в то время как данные из версии Original существующей строки переопределяются данными из версии Original входной строки.When PreserveChanges is true, the data from the existing row is maintained in the Current row version of the existing row, while the data from the Original row version of the existing row is overwritten with the data from the Original row version of the incoming row. RowState существующей строки установлен в Modified.The RowState of the existing row is set to Modified. Применяются следующие исключения:The following exceptions apply:

  • Если существующая строка имеет версию RowState``Deleted, это RowState остается Deleted и не устанавливается в Modified.If the existing row has a RowState of Deleted, this RowState remains Deleted and is not set to Modified. В этом случае данные из входной строки будут сохраняться в версии Original существующей строки, переопределяя версию Original существующей строки (если только входная строка не имеет RowState, равное Added).In this case, the data from the incoming row will still be stored in the Original row version of the existing row, overwriting the Original row version of the existing row (unless the incoming row has a RowState of Added).

  • Если входная строка имеет состояние RowState, равное Added, данные из версии Original существующей строки не переопределяются данными из входной строки, т. к. входная строка не имеет версии Original.If the incoming row has a RowState of Added, the data from the Original row version of the existing row will not be overwritten with data from the incoming row, because the incoming row does not have an Original row version.

Если PreserveChanges равно false, версии строк Current и Original в существующей строке переопределяются данными из входной строки, а состояние RowState существующей строки устанавливается в состояние RowState входной строки.When PreserveChanges is false, both the Current and Original row versions in the existing row are overwritten with the data from the incoming row, and the RowState of the existing row is set to the RowState of the incoming row. Применяются следующие исключения:The following exceptions apply:

  • Если входная строка имеет значение RowState, равное Unchanged, а существующая строка имеет значение RowState, равное Modified, Deleted или Added, состояние RowState существующей строки устанавливается в Modified.If the incoming row has a RowState of Unchanged and the existing row has a RowState of Modified, Deleted, or Added, the RowState of the existing row is set to Modified.

  • Если входная строка имеет состояние RowState, равное Added, а существующая строка имеет состояние RowState, равное Unchanged, Modified или Deleted, состояние RowState существующей строки устанавливается в Modified.If the incoming row has a RowState of Added, and the existing row has a RowState of Unchanged, Modified, or Deleted, the RowState of the existing row is set to Modified. Также данные из версии Original существующей строки не переопределяются данными из входной строки, т. к. входная строка не имеет версии Original.Also, the data from the Original row version of the existing row is not overwritten with data from the incoming row, because the incoming row does not have an Original row version.

Параметр MissingSchemaActionMissingSchemaAction

Можно использовать необязательный параметр MissingSchemaAction метода Merge для задания того, как Merge будет обрабатывать элементы схемы во входных данных, не являющихся частью существующего объекта DataSet.You can use the optional MissingSchemaAction parameter of the Merge method to specify how Merge will handle schema elements in the incoming data that are not part of the existing DataSet.

В следующей таблице описываются параметры для MissingSchemaAction.The following table describes the options for MissingSchemaAction.

Параметр MissingSchemaActionMissingSchemaAction option ОписаниеDescription
Add Добавление новых данных схемы в объект DataSet и заполнение новых столбцов входными значениями.Add the new schema information to the DataSet and populate the new columns with the incoming values. Это значение по умолчанию.This is the default.
AddWithKey Добавление новых данных схемы и первичного ключа в объект DataSet и заполнение новых столбцов входными значениями.Add the new schema and primary key information to the DataSet and populate the new columns with the incoming values.
Error Инициация исключения, если встречаются несовпадающие данные схемы.Throw an exception if mismatched schema information is encountered.
Ignore Пропуск новых данных схемы.Ignore the new schema information.

ОграниченияConstraints

При выполнении метода Merge ограничения не проверяются, пока все новые данные не будут добавлены в существующий объект DataSet.With the Merge method, constraints are not checked until all new data has been added to the existing DataSet. После добавления данных ограничения принудительно применяются на текущих значениях в объекте DataSet.Once the data has been added, constraints are enforced on the current values in the DataSet. Необходимо быть уверенным в том, что код обрабатывает все исключения, которые могут инициироваться из-за нарушений ограничений.You must ensure that your code handles any exceptions that might be thrown due to constraint violations.

Рассмотрим случай, когда существующая строка в DataSet является строкой Unchanged со значением первичного ключа, равным 1.Consider a case where an existing row in a DataSet is an Unchanged row with a primary key value of 1. Во время выполнения операции слияния с входной строкой Modified со значением первичного ключа Original, равным 2, и значением первичного ключа Current, равным 1, существующая строка и входная строка не считаются совпадающими, так как различаются значения первичных ключей Original.During a merge operation with a Modified incoming row with an Original primary key value of 2 and a Current primary key value of 1, the existing row and the incoming row are not considered matching because the Original primary key values differ. Однако после завершения объединения и проверки ограничений появится исключение, т. к. значения первичного ключа Current нарушают ограничение уникальности для столбца первичного ключа.However, when the merge is completed and constraints are checked, an exception will be thrown because the Current primary key values violate the unique constraint for the primary key column.

Примечание

Если строки вставляются в таблицу базы данных, содержащую столбец, автоматически увеличивающий свое значение, например столбец идентификаторов, то возвращаемое вставкой значение столбца идентификаторов может не совпадать со значением в объекте DataSet, в результате чего возвращаемые строки не объединяются, а присоединяются.When rows are inserted into a database table containing an auto incrementing column such as an identity column, the identity column value returned by the insert may not match the value in the DataSet, causing the returned rows to be appended instead of merged. Дополнительные сведения см. в разделе Получение значений Identity или автонумерации.For more information, see Retrieving Identity or Autonumber Values.

В следующем примере кода два DataSet объекта с разными схемами объединяются в одну DataSet с объединенными схемами двух входящих DataSet объектов.The following code example merges two DataSet objects with different schemas into one DataSet with the combined schemas of the two incoming DataSet objects.

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

В следующем примере кода берется существующий объект DataSet с обновлениями и эти обновления передаются в DataAdapter, чтобы выполнить обработку в источнике данных.The following code example takes an existing DataSet with updates and passes those updates to a DataAdapter to be processed at the data source. Затем результаты объединяются в исходный объект DataSet.The results are then merged into the original DataSet. После отклонения изменений, в результате которых возникла ошибка, объединенные изменения фиксируются при помощи AcceptChanges.After rejecting changes that resulted in an error, the merged changes are committed with 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();

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()

protected static void OnRowUpdated(
    object sender, SqlRowUpdatedEventArgs args)
{
    if (args.Status == UpdateStatus.ErrorsOccurred)
    {
        args.Row.RowError = args.Errors.Message;
        args.Status = UpdateStatus.SkipCurrentRow;
    }
}
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

См. такжеSee also