Unione del contenuto di un DataSet (ADO.NET)

È possibile utilizzare il metodo Merge per unire il contenuto di un oggetto DataSet, DataTable o una matrice DataRow in un DataSet esistente. L'unione di nuovi dati in un DataSet esistente è influenzata da diversi fattori e opzioni.

Chiavi primarie

Se la tabella che riceve i nuovi dati e lo schema da un'operazione di unione dispone di una chiave primaria, le nuove righe dei dati in arrivo verranno associate alle righe esistenti i cui valori di chiave primaria Original corrispondono a quelli presenti nei dati in arrivo. Se le colonne dello schema in arrivo corrispondono alle colonne dello schema esistente, i dati delle righe esistenti verranno modificati. Le colonne che non corrispondono allo schema esistente verranno ignorate o aggiunte in base al parametro MissingSchemaAction. Le nuove righe contenenti valori di chiave primaria non corrispondenti a nessuna delle righe esistenti verranno aggiunte alla tabella esistente.

Se alle righe in arrivo o esistenti è associato uno stato di riga Added, i relativi valori di chiave primaria verranno associati tramite il valore di chiave primaria Current della riga Added, poiché non è presente nessuna versione di riga Original.

Se in una tabella in arrivo e una tabella esistente è contenuta una colonna con lo stesso nome ma con tipi di dati diversi, verranno generati un'eccezione e l'evento MergeFailed del DataSet. Se nella tabella in arrivo e nella tabella esistente sono state definite chiavi, ma le chiavi primarie sono relative a colonne diverse, verranno generati un'eccezione e l'evento MergeFailed del DataSet.

Se la tabella che riceve i nuovi dati da un'operazione di unione non dispone di alcuna chiave primaria, non sarà possibile associare i nuovi valori relativi ai dati in arrivo alle righe esistenti della tabella. Tali valori verranno quindi aggiunti alla tabella esistente.

Nomi di tabella e spazi dei nomi

Se necessario, agli oggetti DataTable è possibile assegnare un valore della proprietà Namespace. Quando vengono assegnati i valori di Namespace, un oggetto DataSet può contenere più oggetti DataTable con lo stesso valore TableName. Durante le operazioni di unione vengono utilizzati TableName e Namespace per identificare la destinazione di un'unione. Se è stato assegnato Namespace, per identificare la destinazione di un'unione viene utilizzato TableName.

NotaNota

Questo comportamento è stato modificato in .NET Framework versione 2.0.Nella versione 1.1 gli spazi dei nomi sono supportati ma vengono ignorati durante le operazioni di unione.Per questo motivo il comportamento di un oggetto DataSet che utilizza i valori della proprietà Namespace a seconda della versione di .NET Framework in esecuzione.Ad esempio, si supponga di disporre di due DataSets contenenti DataTables con lo stesso valore della proprietà TableName ma valori diversi della proprietà Namespace.Nella versione 1.1 di .NET Framework, i diversi nomi di Namespace verranno ignorati durante l'unione dei due oggetti DataSet.A partire dalla versione 2.0, invece, in seguito all'unione vengono creati due nuovi oggetti DataTables nell'oggetto DataSet di destinazione.I DataTables originali non verranno interessati dall'unione.

PreserveChanges

Quando si passa una matrice DataSet, DataTable o DataRow al metodo Merge, è possibile includere parametri facoltativi che consentano di specificare se mantenere o meno le modifiche nel DataSet esistente e come gestire i nuovi elementi dello schema individuati nei dati in arrivo. Il primo di tali parametri successivi ai dati in arrivo è un flag booleano, PreserveChanges, che consente di specificare se conservare o meno le modifiche nel DataSet esistente. Se il flag PreserveChanges è impostato su true, i valori esistenti nella versione di riga Current della riga esistente non verranno sovrascritti dai valori in arrivo. Se il flag PreserveChanges è impostato su false, i valori esistenti nella versione di riga Current della riga esistente verranno sovrascritti dai valori in arrivo. Se non è specificato, il flag PreserveChanges viene impostato su false per impostazione predefinita. Per ulteriori informazioni sulle versioni di righe, vedere Stati delle righe e versioni delle righe.

Se PreserveChanges è true, i dati della riga esistente verranno mantenuti nella versione di riga Current della riga esistente, mentre i dati della versione di riga Original della riga esistente verranno sovrascritti dai dati della versione di riga Original della riga in arrivo. La proprietà RowState della riga esistente è impostata su Modified. Vengono applicate le seguenti eccezioni:

  • Se il valore di RowState per la riga esistente è Deleted, il valore di RowState rimane Deleted e non viene impostato su Modified. In questo caso i dati contenuti nella riga in arrivo verranno archiviati comunque nella versione di riga Original della riga esistente, sovrascrivendo la versione di riga Original della riga esistente (a meno che il valore di RowState per la riga in arrivo non sia Added).

  • Se il valore di RowState per la riga in arrivo è Added, i dati della versione di riga Original della riga esistente non verranno sovrascritti con i dati della riga in arrivo, poiché a tale riga non è associata nessuna versione di riga Original.

Se PreserveChanges è false, le versioni di riga Current e Original della riga esistente verranno sovrascritte con i dati della riga in arrivo e il valore di RowState della riga esistente verrà impostato sul valore di RowState della riga in arrivo. Vengono applicate le seguenti eccezioni:

  • Se il valore di RowState per la riga in arrivo è Unchanged e il valore di RowState per la riga esistente è Modified, Deletedo Added, il valore di RowState per la riga esistente verrà impostato su Modified.

  • Se il valore di RowState per la riga in arrivo è Added e il valore di RowState per la riga esistente è Unchanged, Modified o Deleted, il valore di RowState per la riga esistente verrà impostato su Modified. I dati contenuti nella versione di riga Original della riga esistente non verranno inoltre sovrascritti con i dati della riga in arrivo, poiché a tale riga non è associata nessuna versione di riga Original.

MissingSchemaAction

È possibile utilizzare il parametro facoltativo MissingSchemaAction del metodo Merge per specificare in che modo Merge gestirà gli elementi dello schema nei dati in arrivo che non fanno parte del DataSet esistente.

Nella tabella seguente vengono descritte le opzioni per MissingSchemaAction.

Opzione MissingSchemaAction

Descrizione

Add

Aggiunge le nuove informazioni dello schema all'oggetto DataSet e popola le nuove colonne utilizzando i valori in arrivo. Questo è il valore predefinito.

AddWithKey

Aggiunge le nuove informazioni sullo schema e sulla chiave primaria al DataSet e popola le nuove colonne utilizzando i valori in arrivo.

Error

Genera un'eccezione nel caso in cui vengano rilevate delle informazioni relative allo schema non associate correttamente.

Ignore

Ignora le nuove informazioni relative allo schema.

Vincoli

Se si utilizza il metodo Merge, la verifica dei vincoli viene eseguita solo quando tutti i nuovi dati sono stati aggiunti all'oggetto DataSet esistente. Una volta aggiunti i dati, i vincoli vengono applicati ai valori correnti del DataSet. È necessario assicurarsi che il codice sia in grado di gestire eventuali eccezioni generate a causa di violazioni dei vincoli.

Si consideri il caso in cui una riga esistente di un DataSet è una riga Unchanged con un valore di chiave primaria di 1. Durante un'operazione di unione con una riga in arrivo Modified in cui il valore di chiave primaria Original è 2 il valore di chiave primaria Current è 1, la riga esistente e la riga in arrivo non vengono considerate corrispondenti perché i valori della chiave primaria di Original sono diversi. Tuttavia, una volta completata l'unione e verificati i vincoli, verrà generata un'eccezione, poiché i valori di chiave primaria Current violano il vincolo univoco per la colonna di chiave primaria.

NotaNota

Quando si inseriscono righe in una tabella di database contenente una colonna a incremento automatico ad esempio una colonna Identity, è possibile che il valore della colonna Identity restituito dall'inserimento non corrisponda al valore di DataSet, pertanto le righe restituite verranno aggiunte anziché unite.Per ulteriori informazioni, vedere Recupero dei valori Identity o Autonumber (ADO.NET).

Nell'esempio di codice seguente due oggetti DataSet con schemi diversi vengono uniti in un unico DataSet contenente una combinazione degli schemi dei due oggetti DataSet in arrivo.

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

Nell'esempio di codice seguente viene selezionato un DataSet esistente con aggiornamenti e tali aggiornamenti vengono passati a un DataAdapter per l'elaborazione nell'origine dati. I risultati vengono quindi uniti nel DataSet originale. Dopo aver rifiutato le modifiche che causavano un errore, le modifiche unite vengono confermate tramite 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;
    }
}

Vedere anche

Concetti

Stati delle righe e versioni delle righe

Recupero dei valori Identity o Autonumber (ADO.NET)

Altre risorse

DataSet, DataTable e DataView (ADO.NET)

DataAdapter e DataReader (ADO.NET)

Recupero e modifica di dati in ADO.NET