Partager via


Utilisation de Upsert pour Créer ou Mettre à jour un enregistrement

Vous pouvez réduire la complexité des scénarios d’intégration de données à l’aide du Upsert message. Lorsque vous chargez des données dans Microsoft Dataverse à partir d’un système externe, par exemple dans un scénario d’intégration de données en bloc, vous ne savez peut-être pas si un enregistrement existe déjà dans Dataverse. Dans ces cas, vous ne pouvez pas décider s'il faut utiliser le message Update ou le message Create. Vous devez d’abord récupérer l’enregistrement pour vérifier s’il existe avant d’effectuer l’opération appropriée. Vous pouvez réduire cette complexité et charger des données dans Dataverse plus efficacement en utilisant le message Upsert.

Il y a une pénalité de performance lorsque vous utilisez Upsert au lieu de Create. Si vous êtes certain que l’enregistrement n’existe pas, utilisez Create.

Remarque

Bien que vous puissiez utiliser des valeurs de clé primaire avec Upsert, il est généralement prévu que vous utiliserez d’autres clés, car le cas d’usage courant est des scénarios d’intégration de données. Pour plus d’informations, consultez Utiliser une autre clé pour référencer un enregistrement.

Upsert d’une table élastique

Le comportement des tables élastiques pour Upsert diffère de celui des tables standard. En utilisant des tables élastiques, l’opération Upsert n’appelle ni le message Create ni le message Update selon que l’enregistrement existe déjà. Upsert applique directement les changements dans l’entité.

  • Si l’enregistrement existe : l’opération remplace toutes les données de l’enregistrement avec les données de l’entité. Il n’existe aucun événement Update.
  • Si l’enregistrement n’existe pas : l’opération crée un enregistrement. Il n’existe aucun événement Create.

Ce comportement affecte l’endroit où vous appliquez la logique métier pour les événements. Vous pouvez créer un nouvel enregistrement à l’aide de Createl’un ou l’autreUpsert. Vous pouvez mettre à jour un enregistrement à l’aide de l’un ou de l’autre Update ou Upsert. Si vous devez appliquer une logique cohérente pour Create ou Update dans les tables élastiques, vous devez également inclure cette logique dans Upsert. Pour plus d’informations, consultez Upsert un enregistrement dans une table élastique.

Comprendre le processus upsert pour les tables standard

Le serveur traite les upsert messages. Le Kit de développement logiciel (SDK) pour les classes .NET utilise les mêmes objets que le serveur. Par conséquent, l’explication suivante utilise le Kit de développement logiciel (SDK) pour les classes .NET pour décrire comment le serveur traite une instance de classe UpsertRequest et retourne une instance de classe UpsertResponse .

Les étapes suivantes décrivent la logique de traitement sur le serveur lorsqu’elle reçoit une requête UpsertRequest pour une table standard :

  1. L’instance UpsertRequest arrive avec la propriété cible définie sur une instance Entité contenant les données pour une opération Create ou Update.
  2. S’il existe, Dataverse tente de rechercher l’enregistrement à l’aide de la propriété Entity.Id de l’instance d’entité définie sur la propriété Cible . Sinon, il utilise les autres valeurs de clé de la propriété Entity.KeyAttributes.
  3. Si l’enregistrement existe :
    1. Définissez la TargetEntity.Id sur la valeur de clé primaire de l’enregistrement trouvé.
    2. Supprimez toutes les données de la Target collection Entity.Attributes qui utilise les mêmes clés que la Target collection Entity.KeyAttributes.
    3. Appelez Update.
    4. Définissez la propriété UpsertResponse.RecordCreated sur false.
    5. Créez une EntityReference à partir de l’entité Target comme valeur pour UpsertResponse.Target.
    6. Retourne UpsertResponse.
  4. Si l’enregistrement n’existe pas :
    1. Copiez toutes les données de TargetEntity.KeyAttributes que Targetn’a pas déjà dans sa collection Entity.Attributes dans TargetEntity.Attributes.
    2. Appelez Create.
    3. Définissez UpsertResponse.RecordCreated sur true.
    4. Créez une EntityReference à partir de l’entité Target et le id résultat de l’opération Create comme valeur pour UpsertResponse.Target.
    5. Retourne UpsertResponse.

Le diagramme suivant montre le processus sur le serveur lorsqu’il reçoit une demande UpsertRequest.

Capture d’écran du flux de processus upsert pour les tables standard dans Dataverse.

Conseils pour la rédaction des demandes

Lorsque vous utilisez d’autres clés pour identifier un enregistrement, n’incluez pas les données de clé secondaires dans la partie de la requête qui représente les données à enregistrer.

Si vous utilisez l’API web et que vous ne connaissez pas le Kit de développement logiciel (SDK) pour .NET, le processus côté serveur décrit précédemment peut être difficile à suivre. L’API web n’a pas le même modèle objet que les objets sdk utilisés dans la description et le diagramme précédemment, mais vous pouvez mapper les données comme indiqué dans le tableau suivant.

API Web SDK Description
Valeurs de clés dans l’URL Entity.KeyAttributes, propriété Contient les données de clé alternative pour identifier l’enregistrement.
Corps de la demande L'Entité est définie dans la propriété UpsertRequest.Target Contient les données à utiliser pour Create ou Update.

Bien que le serveur traite ces requêtes comme décrit précédemment, vous pouvez le considérer comme suit :

  • Si l’enregistrement existe : Le serveur supprime le jeu de données dans le corps de la demande pour ces valeurs de clé alternatives dans l’URL, il est donc inutile de l'inclure. Cette pratique garantit que vous ne pouvez pas mettre à jour les valeurs de clé secondaire d’un enregistrement lorsque vous utilisez ces valeurs de clé secondaire pour l’identifier. Vous pouvez modifier d’autres valeurs de clé à l’aide de la clé primaire ou d’un autre ensemble de clés secondaires.
  • Si l’enregistrement n’existe pas : Le serveur utilise toutes les valeurs de clé alternatives définies dans le corps de la requête pour créer le nouvel enregistrement, même si les données sont différentes des valeurs spécifiées par les clés de remplacement dans l’URL. S’il n’existe aucune autre donnée de clé dans le corps de la requête, le serveur copie les données de clé de remplacement de l’URL dans le corps de la requête. Pour éviter une situation où les valeurs de clé dans l’URL et les valeurs de clé correspondantes dans le corps ne correspondent pas, ne les incluez pas dans le corps.

Utiliser l’API web

À l’aide de l’API web, vous pouvez initier les messages Upsert et Update en envoyant une requête HTTP PATCH à une ressource spécifiée EntitySet. Les clés de l’URL identifient la ressource.

La différence entre Upsert et Update dépend de si vous incluez l’en-tête de requête If-Match: *. Si vous incluez l’en-tête If-Match: * de requête et qu’aucune ressource ne correspond aux valeurs de clé dans l’URL, la requête retourne un code d’état 404 Not Found . L’en-tête de la demande If-Match: * garantit que la demande PATCH est une opération Update.

Si vous n’incluez pas l’en-tête If-Match: * de requête, la PATCH demande est traitée comme un Upsert. La demande crée un enregistrement s’il ne trouve aucun enregistrement correspondant aux clés dans l’URL. Toutefois, contrairement au Kit de développement logiciel (SDK), la réponse ne vous indique pas s’il a créé un enregistrement. La réponse du statut est 204 No Content dans les deux cas.

Si vous incluez un en-tête de requête Prefer: return=representation, le système retourne un état 201 Created pour Create, et un état 200 OK pour Update. L’ajout de cet en-tête ajoute une opération supplémentaire Retrieve , ce qui affecte les performances. Si vous utilisez cette option, assurez-vous que l’option de requête $select que vous ajoutez inclut uniquement la valeur de la clé primaire. Pour en savoir plus, consultez :

À l’aide d’une PATCH demande, vous pouvez également inclure l’en-tête de requête If-None-Match: * pour bloquer un Update si vous souhaitez seulement créer des enregistrements. Pour plus d’informations, consultez Limiter les opérations upsert.

Exemple de code d’API web

Les exemples suivants montrent les Upsert opérations à l’aide d’une table avec deux colonnes clés alternatives :

Créer avec upsert

Cette demande crée un enregistrement.

Demande :

PATCH [Organization Uri]/api/data/v9.2/example_records(example_key1=2,example_key2=2) HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json
Content-Type: application/json

{ "example_name": "2:2" }

Réponse :

HTTP/1.1 204 No Content
OData-Version: 4.0
OData-EntityId: [Organization Uri]/api/data/v9.2/example_records(example_key1=2,example_key2=2)

Mettre à jour avec upsert

Cette demande met à jour l’enregistrement créé par la demande précédente.

Demande :

PATCH [Organization Uri]/api/data/v9.2/example_records(example_key1=2,example_key2=2) HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json
Content-Type: application/json

{ "example_name": "2:2 Updated" }

Réponse :

HTTP/1.1 204 No Content
OData-Version: 4.0
OData-EntityId: [Organization Uri]/api/data/v9.2/example_records(example_key1=2,example_key2=2)

Remarque

La réponse est identique pour les opérations de création ou de mise à jour.

Créer avec upsert et return=representation préférence

Quand vous utilisez l’en-tête Prefer: return=representation, vous pouvez obtenir un code de statut différent dans la réponse pour indiquer si l’enregistrement a été créé ou mis à jour.

La requête suivante crée un enregistrement et renvoie le statut 201 Created.

Demande :

PATCH [Organization Uri]/api/data/v9.2/example_records(example_key1=3,example_key2=3)?$select=example_recordid HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json
Prefer: return=representation
Content-Type: application/json

{ "example_name": "3:3" }

Réponse :

HTTP/1.1 201 Created
Content-Type: application/json; odata.metadata=minimal
ETag: W/"71004878"
Preference-Applied: return=representation
OData-Version: 4.0

{
  "@odata.context": "[Organization Uri]/api/data/v9.2/$metadata#example_records(example_recordid)/$entity",
  "@odata.etag": "W/\"71004878\"",
  "example_recordid": "ef0d112e-d70e-ed11-82e5-00224822577b"
}

Mettre à jour avec Upsert et return=representation preference

Cette demande met à jour l’enregistrement créé par la demande précédente et retourne l’état 200 OK pour indiquer qu’il s’agissait d’une opération de mise à jour.

Demande :

PATCH [Organization Uri]/api/data/v9.2/example_records(example_key1=3,example_key2=3)?$select=example_recordid HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json
Prefer: return=representation
Content-Type: application/json

{ "example_name": "3:3 Updated" }

Réponse :

HTTP/1.1 200 OK
Content-Type: application/json; odata.metadata=minimal
ETag: W/"71004880"
OData-Version: 4.0

{
  "@odata.context": "[Organization Uri]/api/data/v9.2/$metadata#example_records(example_recordid)/$entity",
  "@odata.etag": "W/\"71004880\"",
  "example_recordid": "ef0d112e-d70e-ed11-82e5-00224822577b"
}

Utiliser le Kit de développement logiciel (SDK) pour .NET

Votre application cliente utilise la méthode IOrganizationService.Execute avec une instance UpsertRequest dont la propriété Cible est définie avec une instance d’entité contenant les données d’une opération ou Create d’une Update opération. En règle générale, vous définissez la propriété Entity.KeyAttributes sur l’instance d’entité avec des valeurs utilisées pour identifier l’enregistrement à l’aide de clés alternatives.

La propriété UpsertResponse.RecordCreated vous indique si l’enregistrement a été créé, et upsertResponse.Target contient une référence à l’enregistrement créé ou mis à jour.

Kit de développement logiciel (SDK) pour l’exemple de code .NET

Le fichier SampleMethod.cs dans l'exemple Ajouter un enregistrement avec Upsert contient la méthode suivante ProcessUpsert. Cette méthode applique le UpsertRequest message sur le contenu d’un fichier XML pour créer de nouveaux enregistrements ou mettre à jour des enregistrements existants.

public static void ProcessUpsert(CrmServiceClient service, String Filename)
{
    Console.WriteLine("Executing upsert operation.....");
    XmlTextReader tr = new XmlTextReader(Filename);
    XmlDocument xdoc = new XmlDocument();
    xdoc.Load(tr);
    XmlNodeList xnlNodes = xdoc.DocumentElement.SelectNodes("/products/product");

    foreach (XmlNode xndNode in xnlNodes)
    {
        String productCode = xndNode.SelectSingleNode("Code").InnerText;
        String productName = xndNode.SelectSingleNode("Name").InnerText;
        String productCategory = xndNode.SelectSingleNode("Category").InnerText;
        String productMake = xndNode.SelectSingleNode("Make").InnerText;

        //use alternate key for product
        Entity productToCreate = new Entity("sample_product", "sample_productcode", productCode);

        productToCreate["sample_name"] = productName;
        productToCreate["sample_category"] = productCategory;
        productToCreate["sample_make"] = productMake;
        var request = new UpsertRequest()
        {
            Target = productToCreate
        };

        try
        {
            // Execute UpsertRequest and obtain UpsertResponse.
            var response = (UpsertResponse)service.Execute(request);
            if (response.RecordCreated)
                Console.WriteLine("New record {0} is created!", productName);
            else
                Console.WriteLine("Existing record {0} is updated!", productName);
        }

        // Catch any service fault exceptions that Dataverse throws.
        catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>)
        {
            throw;
        }
    }
}

Voir aussi

Utiliser le suivi des modifications pour synchroniser les données avec les systèmes externes
Définir des clés alternatives pour une table
Utilisation d’une clé secondaire pour référencer un enregistrement