Mise à jour de sources de données à l'aide de DataAdapters (ADO.NET)

Mise à jour : November 2007

La méthode Update de l'objet DataAdapter est appelée pour répercuter les modifications d'un objet DataSet dans la source de données. La méthode Update, comme la méthode Fill, prend comme arguments une instance d'un DataSet et un objet DataTable optionnel ou un nom de DataTable. L'instance DataSet est le DataSet qui contient les modifications apportées et le DataTable identifie la table de laquelle les modifications doivent être récupérées. Si aucun DataTable n'est spécifié, le premier DataTable du DataSet est utilisé.

Lorsque vous appelez la méthode Update, le DataAdapter analyse les modifications apportées et exécute la commande appropriée (INSERT, UPDATE ou DELETE). Lorsque le DataAdapter rencontre une modification apportée à un objet DataRow, il utilise la propriété InsertCommand, UpdateCommand, ou DeleteCommand pour traiter la modification. Cela vous permet d'optimiser les performances de votre application ADO.NET en spécifiant la syntaxe de commande au moment du design et, si possible, par le biais de l'utilisation de procédures stockées. Vous devez explicitement définir les commandes avant d'appeler la méthode Update. Si la méthode Update est appelée et si la commande appropriée n'existe pas pour une mise à jour particulière (par exemple, pas de DeleteCommand pour les lignes supprimées), une exception est levée.

Remarque :

Si vous utilisez des procédures stockées SQL Server pour modifier ou supprimer des données à l'aide d'un DataAdapter, assurez-vous que vous n'utilisez pas SET NOCOUNT ON dans la définition de procédure stockée. En effet, le compte des lignes affectées retourné est alors de zéro, ce que le DataAdapter interprète comme un conflit d'accès concurrentiel. Dans ce cas, une exception DBConcurrencyException est levée.

Des paramètres de commande peuvent être utilisés pour spécifier les valeurs d'entrée et de sortie d'une instruction SQL ou d'une procédure stockée pour chaque ligne modifiée dans un DataSet. Pour plus d'informations, voir Paramètres de DataAdapter (ADO.NET).

Remarque :

Il est important de comprendre la différence entre la suppression d'une ligne dans un objet DataTable et la suppression de la ligne. Lorsque vous appelez la méthode Remove ou RemoveAt, la ligne est immédiatement supprimée. Aucune ligne correspondante dans la source de données principale ne sera affectée si vous passez ensuite le DataTable ou le DataSet à un DataAdapter et appelez la méthode Update. Lorsque vous utilisez la méthode Delete, la ligne reste dans le DataTable et est marquée pour suppression. Si vous passez ensuite le DataTable ou le DataSet à un DataAdapter et appelez la méthode Update, la ligne correspondante dans la source de données principale est supprimée.

Si votre DataTable est mappé à une table de base de données unique ou est généré par celle-ci, vous pouvez tirer parti de l'objet DbCommandBuilder pour générer automatiquement les objets DeleteCommand, InsertCommand et UpdateCommand du DataAdapter. Pour plus d'informations, voir Génération de commandes à l'aide de CommandBuilders (ADO.NET).

Utilisation d'UpdatedRowSource pour mapper des valeurs à un DataSet

Vous pouvez contrôler la façon dont les valeurs retournées depuis la source de données sont de nouveau mappées au DataTable suite à un appel de la méthode Update d'un DataAdapter, en utilisant la propriété UpdatedRowSource d'un objet DbCommand. En affectant l'une des valeurs d'énumération UpdateRowSource à la propriété UpdatedRowSource, vous pouvez contrôler si les paramètres de sortie retournés par les commandes DataAdapter sont ignorés ou appliqués à la ligne modifiée dans le DataSet. Vous pouvez aussi spécifier si la première ligne retournée (si elle existe) doit être appliquée à la ligne modifiée dans le DataTable.

Le tableau suivant décrit les différentes valeurs de l'énumération UpdateRowSource et la façon dont elles affectent le comportement d'une commande utilisée avec un DataAdapter.

Énumération UpdatedRowSource

Description

Both

Les paramètres de sortie et la première ligne d'un jeu de résultats retourné peuvent être mappés à la ligne modifiée dans le DataSet.

FirstReturnedRecord

Seules les données de la première ligne d'un jeu de résultats retourné peuvent être mappées à la ligne modifiée dans le DataSet.

None

Les paramètres de sortie ou les lignes d'un jeu de résultats retourné sont ignorés.

OutputParameters

Seuls les paramètres de sortie peuvent être mappés à la ligne modifiée dans le DataSet.

La méthode Update répercute vos modifications dans la source de données, cependant d'autres clients peuvent avoir modifié les données au niveau de la source depuis la dernière fois où vous avez rempli le DataSet. Pour actualiser votre DataSet avec des données en cours, utilisez le DataAdapter et la méthode Fill. De nouvelles lignes seront ajoutées à la table et les informations mises à jour seront incorporées dans les lignes existantes. La méthode Fill détermine si une nouvelle ligne sera ajoutée ou si une ligne existante sera mise à jour en se basant sur les valeurs de clé primaire des lignes du DataSet et des lignes retournées par SelectCommand. Si une valeur de clé primaire d'une ligne du DataSet correspond à celle d'une ligne des résultats retournés par SelectCommand, la méthode Fill met à jour la ligne existante en y insérant les informations de la ligne retournée par SelectCommand et affecte la valeur Unchanged à la propriété RowState. Si la valeur de clé primaire d'une ligne retournée par SelectCommand n'a pas de correspondance dans les lignes du DataSet, la méthode Fill ajoute une nouvelle ligne avec un RowState ayant la valeur Unchanged.

Remarque :

Si SelectCommand retourne les résultats d'un OUTER JOIN, le DataAdapter ne définit pas la valeur PrimaryKey du DataTable résultant. Vous devez définir vous-même la PrimaryKey pour garantir une résolution correcte des lignes dupliquées. Pour plus d'informations, voir Définition des clés primaires (ADO.NET).

Pour gérer les exceptions qui peuvent se produire suite à l'appel de la méthode Update, vous pouvez utiliser l'événement RowUpdated pour répondre aux erreurs de mise à jour des lignes (voir Gestion des événements DataAdapter (ADO.NET)). Vous pouvez aussi affecter la valeur RowUpdated à Gestion des événements DataAdapter (ADO.NET) avant d'appeler Update et répondre aux informations d'erreur stockées dans la propriété RowError d'une ligne particulière lorsque la mise à jour est terminée (voir Informations sur les erreurs de ligne).

Remarque   L'appel de AcceptChanges sur le DataSet, le DataTable ou le DataRow provoquera la substitution de toutes les valeurs Original d'un DataRow par les valeurs Current du DataRow. Si les valeurs de champ qui identifient la ligne comme étant unique ont été modifiées, après l'appel de AcceptChanges, les valeurs Original ne correspondront plus aux valeurs de la source de données. AcceptChanges est appelé automatiquement pour chaque ligne au cours de l'appel de la méthode Update d'un DataAdapter. Vous pouvez conserver les valeurs d'origine au cours d'un appel de la méthode Update en commençant par affecter la valeur false à la propriété AcceptChangesDuringUpdate du DataAdapter, ou en créant un gestionnaire d'événements pour l'événement RowUpdated et en affectant la valeur SkipCurrentRow à Status. Pour plus d'informations, voir Fusion du contenu d'un DataSet (ADO.NET) et Gestion des événements DataAdapter (ADO.NET).

Exemple

Les exemples suivants montrent comment exécuter des mises à jour de lignes modifiées en définissant de manière explicite le UpdateCommand d'un DataAdapter et en appelant sa méthode Update. Notez que le paramètre spécifié dans la clause WHERE de l'instruction UPDATE est défini pour utiliser la valeur Original du SourceColumn. Cela est important car la valeur Current peut avoir été modifiée et ne pas correspondre à la valeur dans la source de données. La valeur Original est la valeur qui a été utilisée pour remplir le DataTable à partir de la source de données.

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

Colonnes AutoIncrement

Si les tables de votre source de données ont des colonnes à incrémentation automatique, vous pouvez remplir les colonnes de votre DataSet soit en retournant la valeur d'auto-incrémentation comme paramètre de sortie d'une procédure stockée et en la mappant à une colonne dans une table, soit en utilisant l'événement RowUpdated du DataAdapter pour exécuter une instruction SELECT supplémentaire. Pour plus d'informations et pour obtenir un exemple, voir Récupération des valeurs des champs Identité ou NuméroAuto (ADO.NET).

Ordre des insertions, mises à jour et suppressions

Dans de nombreuses circonstances, l'ordre dans lequel les modifications apportées dans le DataSet sont transmises à la source de données est important. Par exemple, si une valeur de clé primaire d'une ligne existante est mise à jour et qu'une nouvelle ligne est ajoutée avec la nouvelle valeur de clé primaire en tant que clé primaire, il est important de traiter la mise à jour avant l'insertion.

Vous pouvez utiliser la méthode Select du DataTable pour retourner un tableau DataRow qui fait uniquement référence à des lignes ayant un RowState particulier. Vous pouvez ensuite passer le tableau DataRow retourné à la méthode Update du DataAdapter pour traiter les lignes modifiées. En spécifiant un sous-ensemble des lignes à mettre à jour, vous pouvez contrôler l'ordre dans lequel les insertions, mises à jour et suppressions sont traitées.

Exemple

Le code suivant garantit, par exemple, que seront d'abord traitées les lignes supprimées de la table puis les lignes mises à jour et enfin les lignes insérées.

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

Voir aussi

Concepts

États et versions de ligne

AcceptChanges et RejectChanges

Fusion du contenu d'un DataSet (ADO.NET)

Récupération des valeurs des champs Identité ou NuméroAuto (ADO.NET)

Autres ressources

DataAdapters et DataReaders (ADO.NET)