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 en utilisant le message Upsert. En chargeant des données dans Microsoft Dataverse à partir d’un système externe, par exemple avec un scénario d’intégration de données en bloc, vous pouvez ne pas savoir si un enregistrement existe déjà dans Dataverse. Dans ce cas, vous ne pouvez pas savoir si vous devez utiliser le message Update ou Create. Vous devez récupérer un enregistrement pour déterminer 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é des performances à utiliser Upsert par rapport à Create. Si vous êtes certain que l’enregistrement n’existe pas, utilisez Create.

Notes

Bien que vous puissiez utiliser des valeurs de clé primaire avec Upsert, on s’attend généralement à ce que vous utilisiez des clés alternatives, car le cas d’utilisation courant concerne les scénarios d’intégration de données. Pour plus d’informations : Utilisation d’une clé secondaire pour référencer un enregistrement

Upsert d’une table élastique

Le comportement des tables élastiques pour Upsert est différent des tables standard. Avec les tables élastiques, l’opération Upsert n’appelle pas le message Create ou Update selon que l’enregistrement existe déjà ou non. Upsert applique directement les changements dans l’entité.

  • Si l’enregistrement existe : toutes les données de l’enregistrement sont écrasées par les données de l’entité. Il n’existe aucun événement Update.
  • Si l’enregistrement n’existe pas : un enregistrement est créé. Il n’existe aucun événement Create.

Cela a des implications sur l’endroit où vous appliquez la logique métier pour les événements. Un enregistrement peut être créé en utilisant Create ou Upsert. Un enregistrement peut être mis à jour en utilisant 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. Plus d’informations : Faire un upsert d’un enregistrement dans une table élastique

Comprendre le processus d’upsert pour les tables standard

Les messages Upsert sont traités sur le serveur. Les classes Kit de développement logiciel (SDK) pour .NET utilisent les mêmes objets que ceux utilisés sur le serveur. Par conséquent, l’explication suivante utilise le SDK pour les classes .NET pour décrire comment une instance UpsertRequest est traitée et l’instance UpsertResponse renvoyée.

Les étapes suivantes décrivent la logique de traitement sur le serveur lorsque UpsertRequest est reçu pour une table standard :

  1. L’instance UpsertRequest arrive avec l’instance Target Property définie avec une instance Entity contenant les données d’une opération Create ou Update.
    • L’instance Entity aura généralement la Entity.KeyAttributes Property définie avec des valeurs utilisées pour identifier l’enregistrement à l’aide de clés secondaires.
  2. S’il existe, Dataverse va essayer de rechercher l’enregistrement en utilisant la propriété Entity.Id de l’instance Entity définie sur la propriété Target. Sinon, il utilise les valeurs clé secondaire à partir de Entity.KeyAttributes Property.
  3. Si l’enregistrement existe :
    1. Définissez le Entity.Id Target avec la valeur de la clé primaire de l’enregistrement trouvé.
    2. Supprimez toutes les données de la collection Target Entity.Attributes qui utilisent les mêmes clés que celles utilisées dans la collection Target 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 de la mise à jour comme valeur de UpsertResponse.Target.
    6. Retournez UpsertResponse.
  4. Si l’enregistrement n’existe pas :
    1. Copiez toutes les données de la Target Entity.KeyAttributes que la Target n’a pas déjà dans sa collection Entity.Attributes vers la Target Entity.Attributes.
    2. Appelez Create.
    3. Définissez la propriété UpsertResponse.RecordCreated sur true.
    4. Créez une EntityReference à partir de l’entité Target. Le résultat de l’id de l’opération Create contient la valeur de UpsertResponse.Target.
    5. Retournez UpsertResponse.

Le diagramme suivant montre le processus sur le serveur quand la classe UpsertRequest est reçue.

flux de processus upsert

Conseils pour la rédaction des demandes

Lorsque vous utilisez des clés secondaires pour identifier un enregistrement, il n’est ni recommandé ni nécessaire d’inclure les données de clé secondaire dans la partie de la demande qui représente les données à enregistrer.

Si vous utilisez l’API web et que vous débutez avec le SDK pour .NET, le processus côté serveur décrit ci-dessus peut être difficile à suivre. L’API web n’a pas le même modèle d’objet que les objets Kit de développement logiciel (SDK) utilisés dans la description et le diagramme ci-dessus, mais les données peuvent être mappées comme indiqué dans le tableau ci-dessous.

API Web SDK Description
Valeurs de clés dans l’URL Entity.KeyAttributes Property Contient les données clé secondaire pour identifier l’enregistrement.
Corps de la demande La Entity définie sur la UpsertRequest.Target Property Contient les données à utiliser pour Create ou Update.

Bien que ces requêtes soient traitées sur le serveur comme décrit ci-dessus, vous pouvez y penser de la manière suivante :

  • Si l’enregistrement existe : le jeu de données dans le corps de la requête pour ces valeurs de clé secondaire dans l’URL sont supprimées, donc cela ne sert à rien 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 les valeurs clé secondaire à l’aide de la clé primaire ou d’un ensemble différent de clés alternatives.
  • Si l’enregistrement n’existe pas : toutes les valeurs de clé secondaire définies dans le corps de la requête sont utilisées pour créer l’enregistrement, même si les données sont différentes par rapport aux valeurs spécifiées par les clés secondaires dans l’URL. S’il n’y a pas de données de clé secondaire dans le corps de la requête, les données de clé secondaire de l’URL sont copiées 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, il est préférable de ne pas les inclure du tout dans le corps.

Utilisation de l’API Web

Avec l’API web, les messages Upsert et Update sont tous deux lancés en utilisant PATCH http contre une certaine ressource EntitySet identifiée par les clés dans l’Url.

La différence entre Upsert et Update est défini par le fait que l’en-tête de la demande If-Match: * est inclus. Si l’en-tête de demande If-Match: * est inclus et qu’aucune ressource ne correspond aux valeurs de clé dans l’URL, la requête renvoie un code de statut 404 Not Found. L’en-tête de la demande If-Match: * garantit que la demande PATCH est une opération Update.

Si l’en-tête de la requête If-Match: * n’est pas inclus, la demande PATCH est traitée comme un Upsert et un enregistrement est créé si aucun enregistrement correspondant aux clés de l’URL n’est trouvé. Cependant, contrairement au SDK, la réponse ne vous indique pas si un enregistrement a été créé. La réponse du statut est 204 No Content dans les deux cas.

Si vous incluez un en-tête de demande Prefer: return=representation, le système renvoie un statut 201 Created pour Create et un statut 200 OK pour Update. L’ajout de cet en-tête ajoute une opération Retrieve supplémentaire, ce qui a un impact sur 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 plus d′informations :

Avec une demande PATCH que vous puissiez également inclure l’en-tête de la demande If-None-Match: * pour bloquer une Update si vous souhaitez uniquement créer des enregistrements. Pour plus d’informations, voir : Limiter les opérations upsert

Exemple de code API web

Les exemples suivants montrent des opérations Upsert utilisant une table avec deux colonnes clé secondaire :

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 requête met à jour l’enregistrement créé par la requête ci-dessus.

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)

Notes

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

Créer avec un upsert et une préférence retour=représentation

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 requête met à jour l’enregistrement créé par la requête ci-dessus et renvoie le statut 200 OK pour montrer 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"
}

Utilisation du Kit de développement logiciel (SDK) pour .NET

Votre application cliente utilise la IOrganizationService.Execute Method avec une instance UpsertRequest qui a Target Property défini avec une instance Entity contenant les données pour une opération Create ou Update. L’instance Entity aura généralement la Entity.KeyAttributes Property définie avec des valeurs utilisées pour identifier l’enregistrement à l’aide de clés secondaires.

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

Exemple de code Kit de développement logiciel (SDK) pour .NET

L’exemple Insérer ou mettre à jour un enregistrement à l’aide de Upsert de l’exemple ProductUpsertSample.cs contient la méthode ProcessUpsert suivante pour appliquer le message UpsertRequest du contenu d’un fichier XML pour créer des 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éfinition de clés secondaires pour la table
Utilisation d’une clé secondaire pour référencer un enregistrement

Notes

Pouvez-vous nous indiquer vos préférences de langue pour la documentation ? Répondez à un court questionnaire. (veuillez noter que ce questionnaire est en anglais)

Le questionnaire vous prendra environ sept minutes. Aucune donnée personnelle n’est collectée (déclaration de confidentialité).