Aggiornamenti di origini dati tramite DataAdapter (ADO.NET)

Il metodo Update di DataAdapter viene chiamato per applicare le modifiche apportate a un oggetto DataSet nell'origine dati. Il metodo Update, analogamente al metodo Fill, accetta come argomenti un'istanza di un oggetto DataSet e un oggetto DataTable o nome di DataTable facoltativi. L'istanza di DataSet rappresenta l'oggetto DataSet contenente le modifiche che sono state apportate e l'oggetto DataTable identifica la tabella da cui recuperare le modifiche. Se non viene specificato nessun oggetto DataTable, verrà utilizzato il primo oggetto DataTable di DataSet.

Quando si chiama il metodo Update, DataAdapter analizza le modifiche apportate ed esegue il comando appropriato (INSERT, UPDATE o DELETE). Quando rileva una modifica a un oggetto DataRow, DataAdapter elabora la modifica utilizzando InsertCommand, UpdateCommand o DeleteCommand. In questo modo è possibile ottimizzare le prestazioni dell'applicazione ADO.NET specificando la sintassi del comando in fase di progettazione e, dove possibile, mediante stored procedure. È necessario impostare in modo esplicito i comandi prima di chiamare Update. Se Update viene chiamato e non esiste il comando appropriato per un determinato aggiornamento, ad esempio nessun DeleteCommand per le righe cancellate, viene generata un'eccezione.

NotaNota

Se si utilizzano stored procedure SQL Server per modificare o eliminare dati tramite DataAdapter, assicurarsi di non utilizzare SET NOCOUNT ON nella definizione della stored procedure.Con tale comando il totale restituito delle righe interessate è pari a zero e tale situazione viene interpretata da DataAdapter come un conflitto di concorrenza.In questo caso verrà generata un'eccezione DBConcurrencyException.

È possibile utilizzare i parametri Command per specificare i valori di input e di output di un'istruzione SQL o una stored procedure per ogni riga modificata in un DataSet. Per ulteriori informazioni, vedere Parametri di DataAdapter (ADO.NET).

NotaNota

È importante capire la differenza tra eliminazione di una riga in un oggetto DataTable e rimozione della riga.Quando si chiama il metodo Remove o RemoveAt, la riga viene rimossa immediatamente.Eventuali righe corrispondenti nell'origine dati di back-end non saranno interessate se si passa DataTable o DataSet a un oggetto DataAdapter e si chiama Update.Quando si utilizza il metodo Delete, la riga rimane in DataTable e viene contrassegnato per l'eliminazione.Se quindi si passa DataTable o DataSet a un oggetto DataAdapter e si chiama Update, la riga corrispondente nell'origine dati di back-end verrà eliminata.

Se DataTable esegue il mapping o viene generato da una singola tabella di database, è possibile utilizzare l'oggetto DbCommandBuilder per generare automaticamente gli oggetti DeleteCommand, InsertCommand e UpdateCommand di DataAdapter. Per ulteriori informazioni, vedere Generazione di comandi con CommandBuilder (ADO.NET).

Utilizzo di UpdatedRowSource per eseguire il mapping di valori su un oggetto DataSet

Per controllare come viene eseguito il mapping dei valori restituiti dall'origine dati su un oggetto DataTable in seguito a una chiamata al metodo Update di un oggetto DataAdapter, è possibile utilizzare la proprietà UpdatedRowSource dell'oggetto DbCommand. Impostando la proprietà UpdatedRowSource su uno dei valori di enumerazione UpdateRowSource, è possibile controllare se i parametri restituiti dai comandi di DataAdapter vengono ignorati o applicati alla riga modificata in DataSet. È possibile inoltre specificare se la prima riga restituita (se esiste) viene applicata alla riga modificata in DataTable.

Nella tabella seguente vengono descritti i diversi valori dell'enumerazione UpdateRowSource e viene illustrato il modo in cui influenzano il comportamento di un comando utilizzato con un oggetto DataAdapter.

Enumerazione UpdatedRowSource

Descrizione

Both

È possibile eseguire il mapping dei parametri di output e della prima riga di un set di risultati restituiti sulla riga modificata nell'oggetto DataSet.

FirstReturnedRecord

È possibile eseguire il mapping sulla riga modificata nel DataSet solo dei dati nella prima riga di un set di risultati restituiti.

None

Tutti i parametri di output, o righe, di un set di risultati restituiti vengono ignorati.

OutputParameters

È possibile eseguire il mapping sulla riga modificata nel DataSet solo dei parametri di output.

Il metodo Update applica le modifiche nell'origine dati, ma è possibile che altri client abbiano modificato i dati nell'origine dati dall'ultima volta che è stato compilato il DataSet. Per aggiornare DataSet con i dati correnti, utilizzare i metodi DataAdapter e Fill. Le nuove righe verranno aggiunte alla tabella e le informazioni aggiornate verranno inserite nelle righe esistenti. Quando si esegue il metodo Fill, verrà determinato se aggiungere una nuova riga o aggiornare una riga esistente esaminando i valori delle chiavi primarie delle righe del DataSet e delle righe restituite da SelectCommand. Se il metodo Fill rileva un valore di chiave primaria di una riga del DataSet che corrisponde al valore di chiave primaria di una riga presente nei risultati restituiti da SelectCommand, la riga esistente verrà aggiornata con le informazioni presenti nella riga restituita da SelectCommand e la proprietà RowState della riga esistente verrà impostata su Unchanged. Se una riga restituita da SelectCommand presenta un valore di chiave primaria che non corrisponde ad alcuno dei valori di chiave primaria delle righe del DataSet, il metodo Fill aggiungerà una nuova riga con il valore relativo a RowState impostato su Unchanged.

NotaNota

Se SelectCommand restituisce i risultati di un OUTER JOIN, il DataAdapter non imposterà un valore PrimaryKey per l'oggetto DataTable risultante.Per assicurarsi che le righe duplicate vengano risolte correttamente, sarà necessario definire PrimaryKey in modo autonomo.Per ulteriori informazioni, vedere Definizione di chiavi primarie (ADO.NET).

Per gestire le eccezioni che possono verificarsi quando si chiama il metodo Update, è possibile utilizzare l'evento RowUpdated per rispondere agli errori di aggiornamento delle righe nel momento in cui si verificano (vedere Gestione degli eventi di DataAdapter (ADO.NET)), oppure impostare DataAdapter.ContinueUpdateOnError su true prima di chiamare il metodo Update e rispondere alle informazioni sugli errori archiviate nella proprietà RowError di una determinata riga al termine dell'aggiornamento (vedere Informazioni sugli errori delle righe).

Nota   Se si chiama AcceptChanges sull'oggetto DataSet, DataTable o DataRow, tutti i valori Original relativi a un oggetto DataRow verranno sovrascritti con i valori Current relativi a DataRow. Se i valori di campo che identificano la riga come univoca sono stati modificati, dopo la chiamata a AcceptChanges i valori Original non corrisponderanno più ai valori dell'origine dati. AcceptChanges viene chiamato automaticamente per ogni riga durante una chiamata al metodo Update di un oggetto DataAdapter. Per mantenere i valori originali durante una chiamata al metodo Update, impostare prima la proprietà AcceptChangesDuringUpdate di DataAdapter su false oppure creare un gestore eventi per l'evento RowUpdated e impostare Status su SkipCurrentRow. Per ulteriori informazioni, vedere Unione del contenuto di un DataSet (ADO.NET) e Gestione degli eventi di DataAdapter (ADO.NET).

Esempio

Negli esempi seguenti viene illustrato come aggiornare le righe modificate impostando in modo esplicito UpdateCommand di DataAdapter e chiamando il relativo metodo Update . Notare che il parametro specificato nella clausola WHERE dell'istruzione UPDATE viene impostato in modo da utilizzare il valore Original di SourceColumn. Questo è importante in quanto è possibile che il valore Current sia stato modificato e che non corrisponda più al valore nell'origine dati. Il valore Original è il valore che è stato utilizzato per compilare DataTable dall'origine dati.

Private Sub AdapterUpdate(ByVal connectionString As String)

    Using connection As SqlConnection = New SqlConnection( _
       connectionString)

        Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
          "SELECT CategoryID, CategoryName FROM dbo.Categories", _
          connection)

        adapter.UpdateCommand = New SqlCommand( _
          "UPDATE Categories SET CategoryName = @CategoryName " & _
           "WHERE CategoryID = @CategoryID", connection)

        adapter.UpdateCommand.Parameters.Add( _
           "@CategoryName", SqlDbType.NVarChar, 15, "CategoryName")

        Dim parameter As SqlParameter = _
           adapter.UpdateCommand.Parameters.Add( _
           "@CategoryID", SqlDbType.Int)
        parameter.SourceColumn = "CategoryID"
        parameter.SourceVersion = DataRowVersion.Original

        Dim categoryTable As New DataTable
        adapter.Fill(categoryTable)

        Dim categoryRow As DataRow = categoryTable.Rows(0)
        categoryRow("CategoryName") = "New Beverages"

        adapter.Update(categoryTable)

        Console.WriteLine("Rows after update.")
        Dim row As DataRow
        For Each row In categoryTable.Rows
            Console.WriteLine("{0}: {1}", row(0), row(1))
        Next
    End Using
End Sub
private static void AdapterUpdate(string connectionString)
{
    using (SqlConnection connection =
               new SqlConnection(connectionString))
    {
        SqlDataAdapter dataAdpater = new SqlDataAdapter(
          "SELECT CategoryID, CategoryName FROM Categories",
          connection);

        dataAdpater.UpdateCommand = new SqlCommand(
           "UPDATE Categories SET CategoryName = @CategoryName " +
           "WHERE CategoryID = @CategoryID", connection);

        dataAdpater.UpdateCommand.Parameters.Add(
           "@CategoryName", SqlDbType.NVarChar, 15, "CategoryName");

        SqlParameter parameter = dataAdpater.UpdateCommand.Parameters.Add(
          "@CategoryID", SqlDbType.Int);
        parameter.SourceColumn = "CategoryID";
        parameter.SourceVersion = DataRowVersion.Original;

        DataTable categoryTable = new DataTable();
        dataAdpater.Fill(categoryTable);

        DataRow categoryRow = categoryTable.Rows[0];
        categoryRow["CategoryName"] = "New Beverages";

        dataAdpater.Update(categoryTable);

        Console.WriteLine("Rows after update.");
        foreach (DataRow row in categoryTable.Rows)
        {
            {
                Console.WriteLine("{0}: {1}", row[0], row[1]);
            }
        }
    }
}

Colonne AutoIncrement

Se nelle tabelle dell'origine dati sono presenti colonne con incremento automatico, è possibile riempire le colonne nel DataSet restituendo il valore dell'incremento automatico come un parametro di output di una stored procedure ed eseguendone il mapping su una colonna della tabella, restituendo il valore dell'incremento automatico nella prima riga di un set di risultati restituito da una stored procedure o un'istruzione SQL oppure utilizzando l'evento RowUpdated di DataAdapter per eseguire un'ulteriore istruzione SELECT. Per ulteriori informazioni e per un esempio, vedere Recupero dei valori Identity o Autonumber (ADO.NET).

Ordine di Insert, Update e Delete

In molti casi l'ordine in cui le modifiche apportate mediante DataSet vengono inviate all'origine dati è importante. Se ad esempio il valore di una chiave primaria relativo a una riga esistente viene aggiornato ed è stata aggiunta una nuova riga con il nuovo valore della chiave primaria come chiave esterna, è importante elaborare l'aggiornamento prima di effettuare l'inserimento.

È possibile utilizzare il metodo Select di DataTable per restituire una matrice DataRow che faccia riferimento solo a righe con un particolare RowState. È quindi possibile passare la matrice DataRow restituita al metodo Update di DataAdapter per elaborare le righe modificate. Se si specifica un subset di righe da aggiornare, è possibile controllare l'ordine in cui vengono elaborati gli inserimenti, gli aggiornamenti e le eliminazioni.

Esempio

Il codice seguente, ad esempio, assicura che vengano elaborate prima le righe cancellate della tabella, quindi le righe aggiornate e infine le righe inserite.

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

' First process deletes.
dataSet.Update(table.Select(Nothing, Nothing, _
  DataViewRowState.Deleted))

' Next process updates.
adapter.Update(table.Select(Nothing, Nothing, _
  DataViewRowState.ModifiedCurrent))

' Finally, process inserts.
dataAdpater.Update(table.Select(Nothing, Nothing, _
  DataViewRowState.Added))
DataTable table = dataSet.Tables["Customers"];

// First process deletes.
adapter.Update(table.Select(null, null, DataViewRowState.Deleted));

// Next process updates.
adapter.Update(table.Select(null, null, 
  DataViewRowState.ModifiedCurrent));

// Finally, process inserts.
adapter.Update(table.Select(null, null, DataViewRowState.Added));

Vedere anche

Concetti

Stati delle righe e versioni delle righe

AcceptChanges e RejectChanges

Unione del contenuto di un DataSet (ADO.NET)

Recupero dei valori Identity o Autonumber (ADO.NET)

Altre risorse

DataAdapter e DataReader (ADO.NET)