É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ètreTargets
.
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 :
- InvalidPluginExecutionException(String, Dictionary<String,String>)
- InvalidPluginExecutionException(OperationStatus, String, Dictionary<String,String>)
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é).