Unione di contenuti di dataset
È possibile usare il metodo Merge per unire il contenuto di un oggetto DataSet, DataTable o una matrice DataRow in un DataSet
esistente. Il merge di nuovi dati in un DataSet
esistente è influenzato da diversi fattori e opzioni.
Chiavi primarie
Se la tabella che riceve i nuovi dati e lo schema da un'operazione di merge 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 merge vengono usati TableName e Namespace per identificare la destinazione di un merge. Se è stato assegnato Namespace, per identificare la destinazione di un'unione viene usato TableName.
Nota
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 merge. Per questo motivo il comportamento di un oggetto DataSet che usa 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 altre informazioni sulle versioni delle righe, vedere Stati 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 diRowState
rimaneDeleted
e non viene impostato suModified
. In questo caso i dati contenuti nella riga in arrivo verranno archiviati comunque nella versione di rigaOriginal
della riga esistente, sovrascrivendo la versione di rigaOriginal
della riga esistente (a meno che il valore diRowState
per la riga in arrivo non siaAdded
).Se il valore di
RowState
per la riga in arrivo èAdded
, i dati della versione di rigaOriginal
della riga esistente non verranno sovrascritti con i dati della riga in arrivo, poiché a tale riga non è associata nessuna versione di rigaOriginal
.
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 diRowState
per la riga esistente èModified
,Deleted
oAdded
, il valore diRowState
per la riga esistente verrà impostato suModified
.Se il valore di
RowState
per la riga in arrivo èAdded
e il valore diRowState
per la riga esistente èUnchanged
,Modified
oDeleted
, il valore diRowState
per la riga esistente verrà impostato suModified
. I dati contenuti nella versione di rigaOriginal
della riga esistente non verranno inoltre sovrascritti con i dati della riga in arrivo, poiché a tale riga non è associata nessuna versione di rigaOriginal
.
MissingSchemaAction
È possibile usare 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 al DataSet e popola le nuove colonne usando i valori in arrivo. Si tratta dell'impostazione predefinita. |
AddWithKey | Aggiunge le nuove informazioni sullo schema e sulla chiave primaria al DataSet e popola le nuove colonne usando 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 usa il metodo Merge
, la verifica dei vincoli viene eseguita solo quando tutti i nuovi dati sono stati aggiunti al 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.
Nota
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 altre informazioni, vedere Recupero di valori di identità o di numerazione automatica.
Nell'esempio di codice seguente viene eseguito il merge di due oggetti DataSet
con schemi diversi in un unico DataSet
contenente una combinazione degli schemi dei due oggetti DataSet
in arrivo.
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
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
.
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