Mesclando conteúdo do DataSet

Você pode usar o método Merge para mesclar o conteúdo de uma matriz DataSet, DataTable ou DataRow em um DataSet existente. Vários fatores e opções afetam a maneira como os novos dados são mesclados em um DataSet existente.

Chaves primárias

Se a tabela que recebe novos dados e esquemas de uma mesclagem tiver uma chave primária, as novas linhas de dados de entrada coincidirão com linhas existentes que tenham os mesmos valores de chave primária Original que nos dados de entrada. Se as colunas do esquema de entrada coincidem com as do esquema existente, os dados nas linhas existentes são modificados. As colunas que não correspondem ao esquema existente são ignoradas ou adicionadas com base no parâmetro MissingSchemaAction. As novas linhas com valores de chave primária que não correspondem a linhas existentes são adicionadas à tabela existente.

Se o estado de linha das linhas novas ou existentes for Added, seus valores de chave primária serão correspondidos usando o valor de chave primária Current da linha Added pois não existe versão da linha Original.

Se uma tabela de entrada e uma tabela existente contiverem uma coluna com o mesmo nome, mas tipos de dados diferentes, uma exceção será gerada e o evento MergeFailed de DataSet será gerado. Se uma tabela de entrada e uma tabela existente tiverem chaves definidas, mas as chaves primárias forem para colunas diferentes, uma exceção será gerada e o evento MergeFailed de DataSet será gerado.

Se a tabela que recebe novos dados de uma mesclagem não tem uma chave primária, as novas linhas de dados de entrada não podem coincidir com linhas existentes na tabela e são adicionadas à tabela existente.

Nomes de tabela e namespaces

Os objetos DataTable podem opcionalmente receber um valor de propriedade Namespace. Quando os valores Namespace são atribuídos, um DataSet pode conter vários objetos DataTable com o mesmo valor TableName. Durante operações de mesclagem, TableName e Namespace são usados para identificar o destino de uma mesclagem. Se nenhum Namespace foi atribuído, somente TableName será usado para identificar o destino de uma mesclagem.

Observação

Esse comportamento mudou no .NET Framework versão 2.0. Na versão 1.1, namespaces tinham suporte, mas eram ignorados durante operações de mesclagem. Por esse motivo, um DataSet que usa valores de propriedade Namespace terá comportamentos diferentes de acordo com a versão do .NET Framework executada. Por exemplo, digamos que você tenha dois DataSets contendo DataTables com os mesmos valores de propriedade TableName, mas diferentes valores de propriedades Namespace. No .NET Framework versão 1.1, os nomes diferentes de Namespace serão ignorados na mesclagem dos dois objetos DataSet. No entanto, a partir da versão 2.0, a mesclagem leva à criação de dois novos DataTables no DataSet de destino. O DataTables original não será afetado pela mesclagem.

PreserveChanges

Quando você passa uma matriz de DataSet, de DataTable ou de DataRow para o método Merge, pode incluir parâmetros opcionais que especificam se as alterações devem ou não ser preservadas no DataSet existente, e como tratar novos elementos de esquema encontrados nos dados de entrada. O primeiro desses parâmetros após os dados de entrada é um sinalizador booliano, PreserveChanges, que especifica se as alterações devem ou não ser preservadas no DataSet existente. Se o sinalizador PreserveChanges estiver definido como true, os valores de entrada não substituirão os valores existentes na versão de linha Current da linha existente. Se o sinalizador PreserveChanges estiver definido como false, os valores de entrada substituirão os valores existentes na versão de linha Current da linha existente. Se o sinalizador PreserveChanges não for especificado, ele será definido como false por padrão. Para obter mais informações sobre versões de linha, consulte Estados de linha e versões de linha.

Quando PreserveChanges é true, os dados da linha existente são mantidos na versão de linha Current da linha existente, enquanto os dados da versão de linha Original da linha existente são substituídos pelos dados da versão de linha Original da nova linha. O RowState da linha existente é definido como Modified. As seguintes exceções se aplicam:

  • Se a linha existente tem um RowState de Deleted, este RowState permanece Deleted e não é definido como Modified. Nesse caso, os dados da nova linha ainda serão armazenados na versão de linha Original da linha existente, substituindo a versão de linha Original da linha existente (a menos que a nova linha tenha um RowState de Added).

  • Se a nova linha tem RowState de Added, os dados da versão de linha Original da linha existente não serão substituídos pelos dados da nova linha, pois a nova linha não tem uma versão de linha Original.

Quando PreserveChanges é false, as versões de linha Current e Original na linha existente são substituídas pelos dados da nova linha, e RowState da linha existente é definido como o RowState da nova linha. As seguintes exceções se aplicam:

  • Se a nova linha tem um RowState de Unchanged e a linha existente tem um RowState de Modified, de Deleted ou de Added, o RowState da linha existente é definido como Modified.

  • Se a nova linha tem um RowState de Added e a linha existente tem um RowState de Unchanged, de Modified ou de Deleted, o RowState da linha existente é definido como Modified. Além disso, os dados da versão de linha Original da linha existente não são substituídos pelos dados da nova linha, pois a nova linha não tem uma versão de linha Original.

MissingSchemaAction

Você pode usar o parâmetro opcional MissingSchemaAction do método Merge para especificar como Merge tratará os elementos de esquema nos dados de entrada que não fazem parte do DataSet existente.

A tabela a seguir descreve as opções de MissingSchemaAction.

Opção MissingSchemaAction Descrição
Add Adicionar as novas informações de esquema ao DataSet e preencher as novas colunas com os valores de entrada. Esse é o padrão.
AddWithKey Adicionar as novas informações de esquema e de chave primária ao DataSet e preencher as novas colunas com os valores de entrada.
Error Gere uma exceção se forem encontradas informações de esquema incompatíveis.
Ignore Ignorar as novas informações do esquema.

Restrições

Com o método Merge, as restrições não são verificadas até que todos os novos dados sejam adicionados ao DataSet existente. Após a adição dos dados, as restrições são impostas nos valores atuais no DataSet. Você deve garantir que seu código trate quaisquer exceções que possam ser geradas por causa de violações de restrição.

Considere um caso onde uma linha existente em um DataSet seja uma linha Unchanged com um valor de chave primária de 1. Durante uma operação de mesclagem com uma nova linha Modified com um valor de chave primária Original de 2 e um valor de chave primária Current de 1, a linha existente e a nova linha não são consideradas coincidentes porque os valores de chave primária Original diferem. Entretanto, quando a mesclagem é concluída e restrições são verificadas, uma exceção é gerada pois os valores de chave primária Current violam a restrição exclusiva para a coluna de chave primária.

Observação

Quando linhas são inseridas em uma tabela de banco de dados contendo uma coluna de incremento automático, como uma coluna de identidade, o valor da coluna de identidade retornado pela inserção talvez não corresponda ao valor no DataSet, causando as linhas retornados a serem adicionadas, e não mescladas. Para obter mais informações, consulte Recuperar valores de identidade ou numeração automática.

O exemplo de código a seguir mescla dois objetos DataSet com esquemas diferentes em um DataSet com os esquemas combinados dos dois objetos DataSet de entrada.

using (SqlConnection connection =
           new(connectionString))
{
    SqlDataAdapter adapter =
        new(
        "SELECT CustomerID, CompanyName FROM dbo.Customers",
        connection);

    connection.Open();

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

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

    customers.Merge(orders, true, MissingSchemaAction.AddWithKey);
Using connection As SqlConnection = New SqlConnection( _
   connectionString)

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

    connection.Open()

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

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

    customers.Merge(orders, True, MissingSchemaAction.AddWithKey)
End Using

O exemplo de código a seguir usa um DataSet existente com atualizações e passa essas atualizações para um DataAdapter a serem processadas na fonte de dados. Os resultados são mesclados no DataSet original. Após a rejeição das alterações que resultaram em um erro, as alterações mescladas são confirmadas com AcceptChanges.

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

// Make modifications to the Customers table.

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

// Add an event handler to handle the errors during Update.
adapter.RowUpdated += 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

Confira também