Partager via


Écrire des plug-ins pour CreateMultiple et UpdateMultiple

Notes

Les messages CreateMultiple et UpdateMultiple sont déployés. Toutes les tables prenant en charge Create et Update soutiennent finalement CreateMultiple et UpdateMultiple, mais certaines tables peuvent ne pas encore les prendre en charge. En savoir plus sur les messages d’opération en bloc

Vous devez écrire des plug-ins pour les messages CreateMultiple et UpdateMultiple avec des tables où des enregistrements peuvent avoir besoin d’être créés ou mis à jour en masse, ou lorsque les performances de création et de mise à jour d’un grand nombre d’enregistrements sont importantes. Presque toutes les tables qui stockent des données d’entreprise peuvent devoir être créées ou mises à jour en masse.

Si vous avez des plug-ins existants pour les messages Create et Update pour des tables comme celles-ci, vous devez les migrer pour utiliser CreateMultiple et UpdateMultiple à la place.

La mise à jour des plug-ins est-elle nécessaire ?

Vous n’êtes pas obligé de migrer vos plug-ins pour utiliser CreateMultiple et UpdateMultiple au lieu de Create et Update. Votre logique continue d’être appliquée lorsque les applications utilisent CreateMultiple ou UpdateMultiple. Il n’est pas nécessaire de migrer vos plug-ins, car le pipeline de traitement des messages Dataverse fusionne la logique des plugins écrite pour la version unique ou multiple de ces messages.

Cependant, seuls les plug-ins écrits pour la version multiple de ces messages obtiennent une amélioration significative des performances. Au fil du temps, à mesure que de plus en plus de développeurs choisissent d’optimiser les performances en utilisant les messages CreateMultiple et UpdateMultiple messages, nous nous attendons à ce que l’écriture de plug-ins pour plusieurs opérations devienne la norme. Les plug-ins écrits pour des opérations uniques seront l’exception.

Qu’est ce qui est different ?

Voici quelques-unes des différences que vous devez gérer lorsque vous migrez vos plug-ins vers les messages CreateMultiple et UpdateMultiple.

Cibles au lieu de Cible

La version multiple de ces messages a un paramètre Targets qui est une EntityCollection plutôt qu’un paramètre Target qui est une Entité unique. Votre code de plug-in doit parcourir les entités de la collection et appliquer une logique à chacune.

Images d’entité

Les images d’entité qui sont configurées dans l’enregistrement d’étape pour vos plug-ins sont un tableau de EntityImageCollection. Ces images d’entité ne sont disponibles que lorsque vous utilisez l’interface IPluginExecutionContext4, qui fournit les propriétés PreEntityImagesCollection et PostEntityImagesCollection. Ces tableaux permettent d’accéder aux mêmes images d’entité dans un tableau synchronisé avec EntityCollection.

Si vous utilisez la classe PluginBase qui est la norme lors de l’initialisation de projets de plug-in à l’aide de Power Platform Tools, puis dans le fichier PluginBase.cs, vous devez remplacer toutes les instances de IPluginExecutionContext avec IPluginExecutionContext4 afin que ces collections d’images d’entités soient disponibles pour votre plug-in.

Important

Lorsque vous configurez les images d’entité pour les étapes de plug-in pour CreateMultiple et UpdateMultiple, il est important de sélectionner avec soin les données de colonne à inclure. Ne sélectionnez pas l’option par défaut de toutes les colonnes. Ces données sont multipliées par le nombre d’entités passées dans le paramètre Targets et contribue à la taille totale du message envoyé au bac à sable. Vous pouvez saisir la limite de taille des messages.

Filtres d’attribut

Pour un plug-in enregistré sur Update ou UpdateMultiple, vous pouvez spécifier des attributs de filtrage à l’étape de l’inscription.

  • Avec Update, le plug-in s’exécute uniquement lorsque l’un des attributs sélectionnés est inclus avec l’entité Target qui est mise à jour.
  • Avec UpdateMultiple, le plug-in s’exécute uniquement lorsque l’un des attributs sélectionnés est inclus dans l’une des entités du paramètre Targets.

Important

Pour UpdateMultiple, vous ne pouvez pas supposer que chaque entité du paramètre Targets contient des attributs qui sont utilisés dans un filtre.

Exemple

Les exemples suivants, un avec une logique de base pour Update et un autre avec une logique pour UpdateMultiple, accèdent aux images d’entité enregistrées avec l’étape.

Cet exemple met à jour l’attribut sample_description avec des informations indiquant si la valeur sample_name a changé. Il fait référence à une image d’entité nommée example_preimage qui a été enregistrée avec l’étape.

// Verify input parameters
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity entity)
{

   // Verify expected entity image from step registration
   if (context.PreEntityImages.TryGetValue("example_preimage", out Entity preImage))
   {

      bool entityContainsSampleName = entity.Contains("sample_name");
      bool entityImageContainsSampleName = preImage.Contains("sample_name");
      bool entityImageContainsSampleDescription = preImage.Contains("sample_description");

      if (entityContainsSampleName && entityImageContainsSampleName && entityImageContainsSampleDescription)
      {
            // Verify that the entity 'sample_name' values are different
            if (entity["sample_name"] != preImage["sample_name"])
            {
               string newName = (string)entity["sample_name"];
               string oldName = (string)preImage["sample_name"];
               string message = $"\\r\\n - 'sample_name' changed from '{oldName}' to '{newName}'.";

               // If the 'sample_description' is included in the update, do not overwrite it, just append to it.
               if (entity.Contains("sample_description"))
               {

                  entity["sample_description"] = entity["sample_description"] += message;

               }
               else // The sample description is not included in the update, overwrite with current value + addition.
               {
                  entity["sample_description"] = preImage["sample_description"] += message;
               }

               // Success:
               localPluginContext.Trace($"Appended to 'sample_description': \"{message}\" ");
            }
            else
            {
               localPluginContext.Trace($"Expected entity and preImage 'sample_name' values to be different. Both are {entity["sample_name"]}");
            }
      }
      else
      {
            if (!entityContainsSampleName)
               localPluginContext.Trace("Expected entity sample_name attribute not found.");
            if (!entityImageContainsSampleName)
               localPluginContext.Trace("Expected preImage entity sample_name attribute not found.");
            if (!entityImageContainsSampleDescription)
               localPluginContext.Trace("Expected preImage entity sample_description attribute not found.");
      }
   }
   else
   {
      localPluginContext.Trace($"Expected PreEntityImage: 'example_preimage' not found.");
   }
}
else
{
   if (!context.InputParameters.Contains("Target"))
      localPluginContext.Trace($"Expected InputParameter: 'Target' not found.");
   if (!(context.InputParameters["Target"] is Entity))
      localPluginContext.Trace($"Expected InputParameter: 'Target' is not Entity.");
}

Gestion des exceptions

Toutes les erreurs qui se produisent dans vos plug-ins doivent être renvoyées à l’aide de InvalidPluginExecutionException. Lorsque votre plug-in lance une exception pour les étapes enregistrées sur les messages CreateMultiple et UpdateMultiple , il convient d’identifier quel enregistrement a provoqué l’échec du plug-in. Pour capturer ces informations, vous devez utiliser l’un de ces constructeurs suivants :

Ces constructeurs vous permettent d’ajouter des valeurs à la propriété InvalidPluginExecutionException.ExceptionDetails, qui ne peut pas être définie directement.

Utilisez le paramètre Dictionary<String,String> exceptionDetails du constructeur pour inclure des informations sur l’enregistrement ayant échoué et toute autre information pertinente.

Définir les détails de l’exception

Pour le message UpdateMultiple, votre code parcourt la propriété EntityCollection Targets et applique une logique à chaque Entité. En cas d’échec, vous pouvez transmettre l’Id de l’enregistrement au constructeur InvalidPluginExecutionException de la manière suivante :

// in plugin code
foreach (Entity entity in Targets)
{
   // [...] When an error occurs:
   var exceptionDetails = new Dictionary<string, string>();
   exceptionDetails.Add("failedRecordId", (string)entity.Id);
   throw new InvalidPluginExecutionException("This is an error message.", exceptionDetails);
}

Ajoutez toute autre information pertinente à l’échec sous forme de paires clé-valeur de chaîne au paramètre exceptionDetails.

Pour CreateMultiple, nous vous recommandons de ne pas définir la valeur de clé primaire pour chaque enregistrement. Dans la plupart des cas, vous devez laisser le système définir cela pour vous, car les valeurs générées par le système sont optimisées pour des performances optimales.

Dans les cas où la valeur de la clé primaire n’est pas définie, s’il n’y a pas d’autre identifiant unique, vous devrez peut-être renvoyer l’index de l’enregistrement ayant échoué dans le paramètre EntityCollection Targets , ou une combinaison de valeurs qui identifient de manière unique l’enregistrement qui échoue. Par exemple, une clé nommée failedRecordIndex indiquant la place de l’enregistrement dans la EntityCollection, ou tout autre identifiant unique utile, peut être ajoutée à exceptionDetails pour aider à résoudre l’échec.

Obtenir les détails de l’exception

Lorsque vous avez inclus des détails sur l’opération défaillante dans la propriété InvalidPluginExecutionException.ExceptionDetails, l’application cliente peut obtenir ces détails à partir de la propriété OrganizationServiceFault.ErrorDetails par le biais de la propriété FaultException<OrganizationServiceFault>.Detail . Le code suivant présente comment :


try
{
   // xMultiple request that triggers your plugin
}
catch (FaultException<OrganizationServiceFault> ex)
{
   ex.Detail.ErrorDetails.TryGetValue("failedRecordId", out object failedRecordId);
}

Si l’application cliente utilise l’API web, elle peut obtenir plus de détails sur les erreurs en définissant l’en-tête de demande Prefer: odata.include-annotations="*".

Remplacer les plug-ins à opération unique dans les solutions

Lorsque vous déployez des enregistrements d’étape de plug-in dans des solutions, il n’existe aucun moyen de forcer la désactivation ou la suppression d’un enregistrement d’étape. Cela rend difficile le remplacement de la logique d’une opération unique par un plug-in à plusieurs opérations.

Lorsque vous déployez une nouvelle étape de plug-in dans une solution pour CreateMultiple ou UpdateMultiple qui remplace une étape de plug-in pour Create ou Update, vous souhaitez réduire la durée pendant laquelle aucune logique ou logique en double n’est appliquée. Vous pouvez désactiver manuellement les étapes pour Create ou Update avant ou après avoir installé la solution. Si vous désactivez avant, il y a une période pendant laquelle aucune logique n’est appliquée. Si vous désactivez après, il y a une période pendant laquelle la logique dupliquée est appliquée. Dans les deux cas, l’organisation peut exiger des temps d’arrêt programmés pour s’assurer que la logique est appliquée de manière cohérente.

Pour minimiser la durée de l’une ou l’autre de ces conditions, nous vous recommandons d’inclure une logique pour désactiver toutes les étapes qui sont remplacées en déployant les nouveaux plug-ins avec Package Deployer. Package Deployer permet d’exécuter le code personnalisé avant, pendant et après l’importation du package dans un environnement. Utilisez ce code pour désactiver les enregistrements d’étape existants.

Voir aussi

Exemple : Plugs-ins CreateMultiple et UpdateMultiple
Messages d’opération en bloc
Exemple : Opérations en bloc SDK pour .NET
Optimiser les performances pour les opérations en bloc

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é).