Partage via


Utiliser les messages d’opération en bloc

Pour obtenir les meilleures performances lorsque vous exécutez des opérations sur plusieurs lignes d’une table Microsoft Dataverse, utilisez un des messages d’opération en bloc suivants :

  • CreateMultiple : crée plusieurs enregistrements du même type dans une seule demande.
  • UpdateMultiple : met à jour plusieurs enregistrements du même type dans une seule demande.
  • UpsertMultiple : crée ou met à jour plusieurs enregistrements du même type dans une seule demande.
  • DeleteMultiple (version préliminaire) : pour tables Elastic uniquement. Supprime plusieurs enregistrements du même type dans une seule demande.

Notes

Pour obtenir des conseils sur les options lors de l’exécution d’opérations en bloc, par exemple quand utiliser ces API par rapport aux API par lots telles que ExecuteMultiple, consultez Optimiser les performances pour les opérations en bloc.

Examples

Les exemples de code suivants montrent comment utiliser les messages d’opération en bloc. Vous pouvez télécharger des exemples depuis github.com/microsoft/PowerApps-Samples :

CreateMultiple

Crée plusieurs enregistrements du même type dans une seule demande.

Utilise la classe CreateMultipleRequest.

/// <summary>
/// Demonstrates the use of the CreateMultiple Message
/// </summary>
/// <param name="service">The authenticated IOrganizationService instance.</param>
/// <param name="recordsToCreate">A list of records of the same table to create.</param>
/// <returns>The Guid values of the records created.</returns>
static Guid[] CreateMultipleExample(IOrganizationService service,
    List<Entity> recordsToCreate)
{

    // Create an EntityCollection populated with the list of entities.
    EntityCollection entities = new(recordsToCreate)
    {
        // All the records must be for the same table.
        EntityName = recordsToCreate[0].LogicalName
    };

    // Instantiate CreateMultipleRequest
    CreateMultipleRequest createMultipleRequest = new()
    {
        Targets = entities,
    };

    // Send the request
    CreateMultipleResponse createMultipleResponse =
                (CreateMultipleResponse)service.Execute(createMultipleRequest);

    // Return the Ids of the records created.
    return createMultipleResponse.Ids;
}

UpdateMultiple

Met à jour plusieurs enregistrements du même type dans une seule demande.

Tout comme pour la mise à jour d’un enregistrement individuel, les données envoyées avec UpdateMultiple ne doivent contenir que les valeurs que vous modifiez. Découvrez comment mettre à jour des enregistrements avec SDK pour .NET et mettre à jour des enregistrements avec l’API web.

Utilise la classe UpdateMultipleRequest.

/// <summary>
/// Demonstrates the use of the UpdateMultiple message.
/// </summary>
/// <param name="service">The authenticated IOrganizationService instance.</param>
/// <param name="recordsToUpdate">A list of records to create.</param>
static void UpdateMultipleExample(IOrganizationService service, List<Entity> recordsToUpdate) {
    // Create an EntityCollection populated with the list of entities.
    EntityCollection entities = new(recordsToUpdate)
    {
        // All the records must be for the same table.
        EntityName = recordsToUpdate[0].LogicalName
    };

    // Use UpdateMultipleRequest
    UpdateMultipleRequest updateMultipleRequest = new()
    {
        Targets = entities,
    };

    service.Execute(updateMultipleRequest);
}

Enregistrements en double dans le paramètre UpdateMultiple Targets

Plusieurs enregistrements avec la même clé primaire ou les mêmes valeurs clé secondaire dans la charge utile ne sont pas pris en charge avec UpdateMultiple. Lorsque plusieurs enregistrements dans le Targets paramètre sont identifiés de manière unique par un primaire ou un clé secondaire, l’opération est effectuée sur le premier enregistrement uniquement. Tous les enregistrements suivants avec les mêmes valeurs de clé dans la charge utile sont ignorés. Ce comportement est différent de UpsertMultiple.

UpsertMultiple

Utilisez Upsert pour intégrer des données avec des sources externes lorsque vous ne savez pas si la table existe dans Dataverse ou non. Les opérations Upsert dépendent fréquemment de clés alternatives pour identifier les enregistrements. Utilisez UpsertMultiple pour exécuter des opérations Upsert en bloc.

Utilise la classe UpsertMultipleRequest.

Cette méthode statique UpsertMultipleExample dépend d’une table samples_bankaccount qui a une colonne de chaîne nommée samples_accountname configurée comme clé secondaire. Il comporte également une colonne de chaîne nommée samples_description. Ce code utilise le constructeur Entité qui définit keyName et keyValue pour spécifier la valeur clé secondaire.

/// <summary>
/// Demonstrates using UpsertMultiple with alternate key values
/// </summary>
/// <param name="service">The authenticated IOrganizationService instance</param>
static void UpsertMultipleExample(IOrganizationService service)
{
    var tableLogicalName = "samples_bankaccount";
    // samples_accountname string column is configued as an alternate key
    // for the samples_bankaccount table
    var altKeyColumnLogicalName = "samples_accountname";

    // Create one record to update with upsert
    service.Create(new Entity(tableLogicalName)
    {
        Attributes =
        {
            {altKeyColumnLogicalName, "Record For Update"},
            {"samples_description","A record to update using Upsert" }
        }
    });

    // Using the Entity constructor to specify alternate key
    Entity toUpdate = new(
            entityName: tableLogicalName,
            keyName: altKeyColumnLogicalName,
            // Same alternate key value as created record.
            keyValue: "Record For Update");
    toUpdate["samples_description"] = "Updated using Upsert";

    Entity toCreate = new(
        entityName: tableLogicalName,
        keyName: altKeyColumnLogicalName,
        keyValue: "Record For Create");
    toCreate["samples_description"] = "A record to create using Upsert";

    // Add the records to a collection
    EntityCollection records = new()
    {
        EntityName = tableLogicalName,
        Entities = { toUpdate, toCreate }
    };

    // Send the request
    UpsertMultipleRequest request = new()
    {
        Targets = records
    };

    var response = (UpsertMultipleResponse)service.Execute(request);

    // Process the responses:
    foreach (UpsertResponse item in response.Results)
    {
        Console.WriteLine($"Record {(item.RecordCreated ? "Created" : "Updated")}");
    }
}

Sortie :

Record Updated
Record Created

La création ou la mise à jour d’un enregistrement dans cet exemple dépend de l’existence ou non d’enregistrements avec la valeur sample_keyattribute correspondante. Aucune donnée n’est renvoyée pour indiquer si un enregistrement a été créé ou mis à jour.

Exemples SDK

Dans Exemple : SDK pour .NET Utiliser des opérations groupées, recherchez le projet UpsertMultiple

Disponibilité

UpsertMultiple est disponible pour les tables prenant en charge CreateMultiple et UpdateMultiple. Cela inclut toutes les tables Elastic. Les requêtes disponibles dans Disponibilité avec les tables standard ne renverront pas de résultats pour UpsertMultiple, mais vous pouvez les utiliser pour détecter si une table prend en charge à la fois CreateMultiple et UpdateMultiple.

Ces requêtes ne renverront pas de résultats pour le message UpsertMultiple. Une table qui prend en charge à la fois CreateMultiple et UpdateMultiple prendra en charge UpsertMultiple.

Enregistrements en double dans le paramètre UpsertMultiple Targets

Plusieurs enregistrements avec la même clé primaire ou les mêmes valeurs clé secondaire dans la charge utile ne sont pas pris en charge avec UpsertMultiple. Lorsque plusieurs enregistrements dans le paramètre Targets sont identifiés de manière unique par une clé principale ou secondaire, UpsertMultiple renverra une erreur. Ce comportement est différent de UpdateMultiple.

Utilisation des tables standard et élastiques

Les tables standard et élastiques voient des avantages significatifs en termes de performances lors de l’utilisation de ces messages d’opération en bloc, mais vous devez les utiliser différemment. Le tableau suivant résume les différences.

Différence Standard Élastique
Nombre d’enregistrements Les opérations sont plus efficaces avec un plus grand nombre d’enregistrements. Il n’y a pas de limite définie sur le nombre d’enregistrements, mais il existe des limites de taille des messages et de temps. Nous vous recommandons d’envoyer 100 à 1 000 enregistrements à la fois. Nous vous recommandons d’envoyer 100 enregistrements à la fois.
Comportement en cas d’erreur Toutes les opérations sont annulées en cas d’erreur. Un succès partiel est possible.
Disponibilité Toutes les tables standard ne prennent pas en charge ces messages. Messages disponibles pour toutes les tables élastiques.
DeleteMultiple Non disponible. Utilisez la classe BulkDeleteRequest du SDK ou l’action BulkDelete de l’API Web à la place. Découvrez comment supprimer des données en bloc. Disponible à l’aide de la classe OrganizationRequest du SDK. L’action DeleteMultiple de l’API web est privée, mais vous pouvez l’utiliser maintenant. Elle sera bientôt rendue public.

L’utilisation de tables standard et élastiques est différente car les tables standard utilisent Azure SQL et prennent en charge les transactions. Les tables élastiques utilisent Azure Cosmos DB, qui ne prend pas en charge les transactions, mais peut gérer de grandes quantités de données à des niveaux de débit élevés avec une faible latence. Les sections suivantes fournissent plus de détails. En savoir plus sur les opérations en bloc sur les tables élastiques.

Nombre d’enregistrements

Le nombre d’enregistrements à joindre à chaque demande dépend de l’utilisation de tables standards ou élastiques.

Conseil

Les tables standard et élastiques ont un meilleur débit lorsque vous envoyez des messages d’opération en bloc en parallèle.

Nombre d’enregistrements avec des tables standard

Les opérations en bloc avec des tables standard sont optimisées pour exécuter des opérations sur plusieurs lignes au sein d’une même transaction. Les opérations deviennent plus efficaces, et donc plus performantes en général, à mesure que le nombre d’opérations par demande augmente. Cette optimisation améliore également l’efficacité des étapes de plug-in enregistrées pour l’opération en bloc. Chaque fois qu’un plug-in est appelé pour une seule opération, quelques millisecondes sont nécessaires pour appeler la classe du plug-in contenant la logique. Lorsqu’un plug-in est enregistré pour un message d’opération en bloc, la classe est appelée une seule fois et peut traiter toutes les opérations plus efficacement. Découvrez comment écrire des plug-ins pour CreateMultiple et UpdateMultiple.

Cet avantage en termes de performances vous incite à envoyer le plus grand nombre d’enregistrements possible dans chaque demande. Cependant, à mesure que le nombre d’enregistrements augmente, la taille de la demande devient plus grande et nécessite un temps de traitement plus long. Finalement, vous rencontrerez la taille des messages et les limites de temps. Si vous atteignez ces limites, toute l’opération échoue. Il n’y a pas de limite définie pour le nombre d’enregistrements à envoyer. Vous pouvez avoir besoin d’expérimenter pour trouver le meilleur nombre. En général, nous estimons que 100 à 1 000 enregistrements par demande est un point de départ raisonnable si la taille des données d’enregistrement est petite et qu’il n’y a pas de plug-ins. Les types d’erreurs que vous pouvez rencontrer peuvent généralement être résolus en envoyant moins d’enregistrements avec chaque demande. Nous vous recommandons d’inclure la possibilité de configurer le nombre d’entités envoyées afin de pouvoir vous adapter en envoyant moins.

Nombre d’enregistrements avec des tables élastiques

Comme il n’y a pas de transaction avec les tables élastiques, il n’y a aucun avantage en termes de performances à essayer d’envoyer le plus grand nombre d’enregistrements par demande. Nous vous recommandons d’envoyer 100 opérations par demande et d’envoyer des demandes en parallèle pour obtenir le débit maximal.

Comportement en cas d’erreur

Le comportement en cas d’erreur dépend de l’utilisation de tables standard ou de tables élastiques.

Comportement en cas d’erreur avec des tables standard

Toute erreur qui se produit dans une opération en bloc avec une table standard entraîne l’annulation de toute l’opération. Vous ne devez utiliser des opérations en bloc avec des tables standard que lorsque vous avez un degré élevé de confiance dans le succès de toutes les opérations. Vous pouvez utiliser une stratégie qui permet à l’ensemble d’opérations d’utiliser la classe ExecuteMultipleRequest du SDK ou l’action $batch de l’API Web pour permettre au jeu d’opérations de revenir si l’opération en bloc échoue. Si le taux de réussite de votre tentative initiale est faible, cette stratégie se traduit par de moins bonnes performances. N’utilisez cette stratégie de retour que lorsque vous vous attendez à ce que la plupart des opérations réussissent.

Comportement en cas d’erreur avec des tables élastiques

Avec les tables élastiques, une opération en bloc peut partiellement réussir. Vous pouvez utiliser les détails de l’erreur pour identifier les enregistrements qui ont échoué.

Lorsque vous utilisez le SDK pour exécuter une opération en bloc avec une table élastique, une exception FaultException de type OrganizationServiceFault est déclenchée en cas d’échec. Utilisez le code suivant pour obtenir le statut de chaque enregistrement.

if (ex.Detail.ErrorDetails.TryGetValue("Plugin.BulkApiErrorDetails", out object errorDetails))
{
    List<BulkApiErrorDetail> bulkApiErrorDetails = JsonConvert.DeserializeObject<List<BulkApiErrorDetail>>(errorDetails.ToString());
}

public class BulkApiErrorDetail
{
    public int RequestIndex { get; set; }
    public string Id { get; set; }
    public int StatusCode { get; set; }
}

Disponibilité

La disponibilité des messages d’opération en bloc dépend de l’utilisation de tables standard ou de tables élastiques. Toutes les tables élastiques prennent en charge les messages CreateMultiple, UpdateMultiple, UpsertMultiple et DeleteMultiple.

Voir aussi :

Disponibilité avec des tables standard

Vous pouvez utiliser les messages d’opération en bloc CreateMultiple et UpdateMultiple pour les tables standard personnalisées et de nombreuses tables standard courantes, mais pas toutes. Vous devez tester si les tables standard individuelles prennent en charge ces messages. Les exemples suivants vous montrent comment y parvenir.

Utilisez cette méthode statique pour détecter si une table donnée prend en charge CreateMultiple ou UpdateMultiple.

/// <summary>
/// Detect whether a specified message is supported for the specified table.
/// </summary>
/// <param name="service">The IOrganizationService instance.</param>
/// <param name="entityLogicalName">The logical name of the table.</param>
/// <param name="messageName">The name of the message.</param>
/// <returns></returns>
public static bool IsMessageAvailable(
    IOrganizationService service,
    string entityLogicalName,
    string messageName)
{
    QueryExpression query = new("sdkmessagefilter")
    {
        ColumnSet = new ColumnSet("sdkmessagefilterid"),
        Criteria = new FilterExpression(LogicalOperator.And)
        {
            Conditions = {
            new ConditionExpression(
                attributeName:"primaryobjecttypecode",
                conditionOperator: ConditionOperator.Equal,
                value: entityLogicalName)
            }
        },
        LinkEntities = {
            new LinkEntity(
                linkFromEntityName:"sdkmessagefilter",
                linkToEntityName:"sdkmessage",
                linkFromAttributeName:"sdkmessageid",
                linkToAttributeName:"sdkmessageid",
                joinOperator: JoinOperator.Inner)
            {
                    LinkCriteria = new FilterExpression(LogicalOperator.And){
                    Conditions = {
                        new ConditionExpression(
                            attributeName:"name",
                            conditionOperator: ConditionOperator.Equal,
                            value: messageName)
                        }
                    }
            }
        }
    };

    EntityCollection entityCollection = service.RetrieveMultiple(query);

    return entityCollection.Entities.Count.Equals(1);
}

Pipelines de messages fusionnés

Chacun des messages d’opération en bloc a un message correspondant qui fonctionne sur des lignes individuelles : Create, Update et Delete. Ces messages existent depuis longtemps et de nombreuses organisations ont une logique personnalisée qui dépend des événements qui se produisent lorsque ces messages sont utilisés.

Une exigence clé pour ces messages d’opération en bloc est que les organisations ne doivent pas maintenir cette logique personnalisée à deux endroits différents. Pour avoir la même logique personnalisée et la conserver au même endroit, nous avons fusionné les pipelines de traitement des messages pour ces messages. Qu’est-ce que cela signifie ?

  • Lorsque le message d’opération en bloc est utilisé, l’événement Create et l’événement Update respectifs se produisent pour chaque instance Entity dans le paramètre Targets. Tous les plug-ins existants ou autres gestionnaires d’événements pour les événements uniques correspondants continuent de fonctionner comme d’habitude. Vous n’avez pas besoin d’écrire de nouveaux plug-ins pour gérer les événements déclenchés par ces messages.

  • Lorsqu’un message d’opération unique est utilisé, l’événement d’opération en bloc respectif se produit avec une EntityCollection contenant une seule instance Entité transmise dans le paramètre Targets. Vous pouvez déplacer toute logique existante qui répond actuellement à des événements d’opération unique vers les événements d’opération en bloc plus efficaces et la logique est appliquée à la fois aux opérations uniques et multiples.

Avant l’introduction des messages d’opération en bloc, toute la logique personnalisée était appliquée aux messages d’opération unique. Cette logique doit continuer à être appliquée lorsque les applications clientes utilisent les messages d’opération en bloc. Pour les tables utilisées avec des opérations en bloc à volume élevé, nous vous recommandons de commencer à déplacer toute logique synchrone existante des événements de message unique vers les événements d’opération en bloc. Si vous introduisez une nouvelle logique, utilisez les événements d’opération en bloc plutôt que les événements d’opération unique.

Attention

Avec cette conception, la logique dupliquée peut potentiellement être appliquée à la fois aux versions uniques et multiples des événements. Dataverse n’essaie pas d’empêcher cela parce que nous ne pouvons pas connaître votre intention.

Il est de votre responsabilité de vous assurer que la même logique appliquée pour la version unique des événements est migrée vers la version multiple de l’événement et supprimée de la version unique de l’événement. Sinon, la logique sera appliquée deux fois.

Découvrez comment écrire des plug-ins pour CreateMultiple et UpdateMultiple.

Limitations

Gardez à l’esprit les limitations suivantes lorsque vous utilisez des messages d’opération en bloc.

Taille des messages et limites de temps

Avec les tables standard, il y a une incitation en termes de performances à envoyer plus d’enregistrements avec chaque demande. Cependant, le nombre d’enregistrements que vous pouvez envoyer est limité par la taille de la charge utile et le temps nécessaire au traitement de l’opération.

Limites de taille du message

Lorsqu’un plug-in est enregistré pour un message, vous pouvez rencontrer l’erreur Taille du message dépassée lors de l’envoi du contexte à Sandbox lorsque la taille totale de la requête dépasse 116,85 Mo. Avec les messages d’opération en bloc, il est plus probable d’atteindre cette limite lorsque vous envoyez des charges utiles plus importantes.

Cette erreur ne se produit pas si aucun plug-in n’est enregistré pour l’événement. Pour éviter l’erreur, désactivez les plug-ins ou envoyez votre requête avec le paramètre facultatif BypassCustomPluginExecution.

Limites de temps

Si vous utilisez le ServiceClient Dataverse, vous pouvez rencontrer cette erreur :

The request channel timed out attempting to send after 00:04:00. 
Increase the timeout value passed to the call to Request or increase the SendTimeout value on the Binding. 
The time allotted to this operation may have been a portion of a longer timeout.

Le délai d’expiration par défaut défini à l’aide de ServiceClient est de 4 minutes, ce qui est long pour toute opération synchrone. Vous pouvez modifier cette valeur à l’aide de la propriété statique ServiceClient.MaxConnectionTimeout. Le délai d’expiration par défaut avec CrmServiceClient est de 2 minutes.

Notes

Avant d’augmenter les limites de temps, vous devez envisager de réduire le nombre d’enregistrements qui sont transmis dans le paramètre Targets.

Non pris en charge pour une utilisation dans les plug-ins

Pour le moment, nous ne prenons pas en charge l’utilisation de messages d’opération en bloc dans le code du plug-in. En savoir plus : Ne pas utiliser les types de demandes par lots dans les plug-ins et les activités de workflow.

Cependant, vous devriez écrire des plug-ins pour les messages CreateMultiple et UpdateMultiple, comme décrit dans Écrire des plug-ins pour CreateMultiple et UpdateMultiple.

Résolution les erreurs courantes

Si vous rencontrez des erreurs lors de l’utilisation d’opérations groupées, veuillez consulter les articles suivants :

Forum aux questions (FAQ)

Si vous n’avez pas trouvé de réponses à vos questions sur l’utilisation des messages d’opération en bloc dans cet article, utilisez le bouton au bas de cet article pour Envoyer et afficher les commentaires pour cette page. Vous avez besoin d’un compte GitHub pour soumettre des commentaires.

Les logiques Retrieve et RetrieveMultiple seront-elles fusionnées ?

Nous ne prévoyons pas de changer le comportement de message Retrieve et RetrieveMultiple. Ceux-ci ont été des messages séparés pendant de nombreuses années et les développeurs ont toujours eu besoin de maintenir une logique pour eux séparément. Tenter de fusionner le pipeline de messages pour eux serait très problématique. En outre, nous vous déconseillons d’appliquer une logique personnalisée à ces messages en raison de l’impact qu’ils peuvent avoir sur les performances.

Comment les limites d’API sont appliquées ?

Il existe deux types de limites d’API. Les messages d’opération en bloc ne fournissent aucun moyen de contourner l’une ou l’autre de ces types.

Limites de la protection des services

Comme décrit dans Limites de l’API de protection des services, les limites ont trois facettes. Deux de ces limites sont évaluées sur une fenêtre glissante de cinq minutes et s’appliquent lors de l’utilisation de ces messages.

  • Nombre de demandes : chaque message d’opération en bloc compte comme une demande unique qui s’accumule dans la limite de 6 000 demandes par utilisateur, par serveur, dans la fenêtre de 5 minutes. Étant donné que ces demandes regroupent des opérations individuelles, la probabilité d’atteindre cette limite est réduite.
  • Temps d’exécution : étant donné que chaque demande de message d’opération en bloc prend généralement plus de temps, et si vous envoyez des demandes en parallèle, vous êtes plus susceptible d’atteindre la limite de temps d’exécution, qui est de 20 minutes par utilisateur, par serveur, dans la fenêtre de 5 minutes.

Limites de demande Power Platform (droits d’API)

Ces limites sont basées sur les modifications de données : opérations Create, Update et Delete. Chaque élément inclus dans le paramètre Targets d’une demande d’opération en bloc s’accumule dans cette limite. En savoir plus sur les limites et allocations de demandes.

Voir aussi

Utiliser UpsertMultiple (version préliminaire)
Utiliser DeleteMultiple (version préliminaire)
Tableaux élastiques
Écrire des plug-ins pour CreateMultiple et UpdateMultiple
Exemple : Opérations en bloc SDK pour .NET
Exemple : Opérations en bloc API web
Exemple : Plugs-ins CreateMultiple et UpdateMultiple
Utilisez les messages avec le SDK pour .NET
Optimiser les performances pour les opérations en bloc