Partager via


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

Vous pouvez utiliser la méthode Merge pour fusionner le contenu d'un tableau DataSet, DataTable ou DataRow dans un DataSet existant. La façon dont les nouvelles données sont fusionnées dans un DataSet existant dépend de plusieurs facteurs et options.

Clés primaires

Si la table qui reçoit les nouvelles données et informations de schéma suite à une fusion dispose d'une clé primaire, les nouvelles lignes des données entrantes sont mises en correspondance avec les lignes existantes ayant les mêmes valeurs de clé primaire Original que celles des données entrantes. Si les colonnes du schéma entrant correspondent à celles du schéma existant, les données des lignes existantes sont modifiées. Les colonnes qui ne correspondent pas au schéma existant sont soit ignorées soit ajoutées en fonction du paramètre MissingSchemaAction. Les nouvelles lignes dont les valeurs de clé primaire ne correspondent à aucune ligne existante sont ajoutées à la table existante.

Si des lignes entrantes ou existantes présentent un état de ligne Added, leurs valeurs de clé primaire sont mises en correspondance à l'aide de la valeur de clé primaire Current de la ligne Added car il n'existe pas de version Original de ces lignes.

Si une table entrante et une table existante contiennent une colonne du même nom, mais dont le type de données diffère, une exception est levée et l'événement MergeFailed du DataSet est déclenché. Si une table entrante et une table existante contiennent toutes deux des clés définies, mais si les clés primaires s'appliquent à des colonnes différentes, une exception est levée et l'événement MergeFailed du DataSet est déclenché.

Si aucune clé primaire n'est définie dans la table qui reçoit les nouvelles données suite à une fusion, les nouvelles lignes des données entrantes ne peuvent pas être mises en correspondance avec les lignes existantes de la table et sont alors ajoutées à la table existante.

Noms de tables et espaces de noms

Une valeur de propriété Namespace peut être assignée à un objet DataTable. Lorsque des valeurs de propriété Namespace sont assignées, un DataSet peut contenir plusieurs objets DataTable avec la même valeur de propriété TableName. Au cours des opérations de fusion, les propriétés TableName et Namespace sont toutes deux utilisées pour identifier la cible d'une fusion. Si aucune propriété Namespace n'a été assignée, seule la propriété TableName est utilisée pour identifier la cible d'une fusion.

RemarqueRemarque

Ce comportement est modifié dans la version 2.0 du .NET Framework.Dans la version 1.1, les espaces de noms étaient pris en charge mais étaient ignorés au cours des opérations de fusion.C'est pourquoi, un objet DataSet qui utilise les valeurs de propriété Namespace aura des comportements différents selon la version du .NET Framework qui est exécutée.Prenons par exemple deux DataSets contenant des DataTables avec les mêmes valeurs de propriété TableName mais des valeurs de propriété Namespace différentes.Dans la version 1.1 du .NET Framework, les noms Namespace différents seront ignorés lors de la fusion de deux objets DataSet.Toutefois, à partir de la version 2.0, la fusion entraîne la création de deux DataTables dans le DataSet cible.Les DataTables d'origine ne seront pas affectés par la fusion.

PreserveChanges

Lorsque vous passez un tableau DataSet, DataTable ou DataRow à la méthode Merge, vous pouvez inclure des paramètres facultatifs pour indiquer s'il convient ou non de conserver les modifications dans le DataSet existant et comment gérer les nouveaux éléments de schéma situés dans les données entrantes. Le premier de ces paramètres après les données entrantes est un indicateur booléen, PreserveChanges, qui indique si les modifications seront ou non conservées dans le DataSet existant. Si l'indicateur PreserveChanges a la valeur true, les valeurs entrantes ne remplacent pas les valeurs existantes dans la version Current de la ligne existante. Si l'indicateur PreserveChanges a la valeur false, les valeurs entrantes remplacent les valeurs existantes dans la version Current de la ligne existante. Si l'indicateur PreserveChanges n'est pas spécifié, il a par défaut la valeur false. Pour plus d'informations sur les versions de lignes, voir États et versions de ligne.

Lorsque PreserveChanges a la valeur true, les données de la ligne existante sont conservées dans la version Current de la ligne existante, alors que les données de la version Original de la ligne existante sont remplacées par les données de la version Original de la ligne entrante. La propriété RowState de la ligne existante prend la valeur Modified. Il existe toutefois certaines exceptions :

  • Si le RowState de la ligne existante est Deleted, ce RowState reste Deleted et ne prend pas la valeur Modified. Dans ce cas, les données de la ligne entrante seront stockées dans la version Original de la ligne existante, remplaçant ainsi la version Original de la ligne existante (sauf si le RowState de la ligne entrante est Added).

  • Si le RowState de la ligne entrante est Added, les données de la version Original de la ligne existante ne seront pas remplacées par les données de la ligne entrante car cette dernière n'a pas de version de ligne Original.

Lorsque PreserveChanges a la valeur false, les versions Current et Original de ligne existante sont remplacées par les données de la ligne entrante et le RowState de la ligne existante prend la valeur du RowState de la ligne entrante. Il existe toutefois certaines exceptions :

  • Si le RowState de la ligne entrante est Unchanged et si le RowState de la ligne existante est Modified, Deleted ou Added, le RowState de la ligne existante prend la valeur Modified.

  • Si le RowState de la ligne entrante est Added et si le RowState de la ligne existante est Unchanged, Modified ou Deleted, le RowState de la ligne existante prend la valeur Modified. De même, les données de la version Original de la ligne existante ne sont pas remplacées par les données de la ligne entrante car cette dernière n'a pas de version de ligne Original.

MissingSchemaAction

Vous pouvez utiliser le paramètre facultatif MissingSchemaAction de la méthode Merge pour spécifier comment Merge va gérer les éléments de schéma présents dans les données entrantes et qui ne font pas partie du DataSet existant.

Le tableau suivant décrit les options de MissingSchemaAction.

Option MissingSchemaAction

Description

Add

Ajoute les nouvelles informations de schéma au DataSet et remplit les nouvelles colonnes avec les valeurs entrantes. Il s'agit de la valeur par défaut.

AddWithKey

Ajoute les nouvelles informations de schéma et de clé primaire au DataSet et remplit les nouvelles colonnes avec les valeurs entrantes.

Error

Lève une exception si une incompatibilité au niveau des informations de schéma est détectée.

Ignore

Ignore les nouvelles informations de schéma.

Contraintes

Avec la méthodeMerge, la vérification des contraintes ne s'effectue qu'une fois toutes les nouvelles données ajoutées au DataSet existant. Les contraintes sont alors appliquées aux valeurs actuelles du DataSet. Vous devez veiller à ce que votre code gère les exceptions levées en cas de violations des contraintes.

Prenons l'exemple d'une ligne Unchanged existante d'un DataSet dont la valeur de clé primaire est 1. Au cours d'une opération de fusion avec une ligne Modified entrante dont la valeur de clé primaire Original est 2 et la valeur de clé primaire Current est 1, la ligne existante et la ligne entrante ne sont pas mises en correspondance car les valeurs de clé primaire Original diffèrent. Cependant, lorsque la fusion est terminée et la vérification des contraintes effectuée, une exception est levée car les valeurs de clé primaire Current enfreignent la contrainte unique définie pour la colonne de clé primaire.

RemarqueRemarque

Lorsque des lignes sont insérées dans une table de base de données contenant une colonne à incrémentation automatique comme une colonne d'identité, la valeur de colonne d'identité retournée par l'insertion peut ne pas correspondre à la valeur du DataSet, ce qui conduit à l'ajout des lignes retournées et non à leur fusion.Pour plus d'informations, voir Récupération des valeurs des champs Identité ou NuméroAuto (ADO.NET).

L'exemple de code suivant fusionne deux objets DataSet contenant des schémas différents pour donner un DataSet dans lequel les schémas des deux objets DataSet entrants sont combinés.

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

L'exemple de code suivant prend un DataSet existant avec des mises à jour et passe ces mises à jour à un DataAdapter pour qu'elles soient traitées au niveau de la source de données. Les résultats sont ensuite fusionnés dans le DataSet d'origine. Après rejet des modifications ayant abouti à une erreur, les modifications fusionnées sont validées avec 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;
    }
}

Voir aussi

Concepts

États et versions de ligne

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

Autres ressources

Objets DataSet, DataTable et DataView (ADO.NET)

DataAdapters et DataReaders (ADO.NET)

Extraction et modification de données dans ADO.NET