• Accueil / Salesforce / Réduction du code…
, Réduction du code de la chaudière de validation sur le terrain<span class="wtr-time-wrap after-title"><span class="wtr-time-number">5</span> minutes de lecture</span>

Réduction du code de la chaudière de validation sur le terrain5 minutes de lecture


Le code Boilerplate est un code que nous répétons souvent avec peu ou pas de variation. Lorsqu’il s’agit d’écrire des validations de champ dans Apex, en particulier dans Apex Triggers, il existe un certain nombre d’exemples de cela. Surtout lorsqu’il s’agit de vérifier si la valeur d’un champ a changé et / ou d’interroger des enregistrements associés, ce qui nécessite également de respecter les bonnes pratiques de bulkifcathion. Ce blog présente un petit cadre de preuve de concept visant à réduire cette logique rendue possible Hiver 21 avec une petite mais critique amélioration de l’environnement d’exécution Apex qui permet aux développeurs d’ajouter dynamiquement des erreurs de champ. De plus, pour ceux qui pratiquent les tests unitaires, l’amélioration permet également de tester affirmer de telles erreurs sans DML!

Ceci est une démonstration très basique du nouveau addError et getErrors méthodes.

Opportunity opp = new Opportunity();
opp.addError('Description', 'Error Message!'); 
List errors = opp.getErrors();
System.assertEquals(1, errors.size());
System.assertEquals('Error Message!', errors[0].getMessage());
System.assertEquals('Description', errors[0].getFields()[0]);

Cependant, pour vraiment apprécier la valeur que ces deux fonctionnalités apportent aux frameworks, examinons d’abord un cas d’utilisation et l’approche traditionnelle du codage d’une telle logique de validation. Nos exigences sont:

  1. Lors de la mise à jour d’un Opportunité valider le La description et Identifiant de compte des champs
  2. Si la Nom de scène le champ devient «Closed Won» et le La description le champ a changé, assurez-vous qu’il n’est pas nul.
  3. Si la Identifiant de compte les changements de champ garantissent que le Nombre d’employés le champ du compte n’est pas nul
  4. Assurez-vous que le code est agrégé et les requêtes ne sont effectuées qu’en cas de besoin.

Le code suivant implémente les exigences ci-dessus, mais contient un code standard.

// Classic style validation
switch on Trigger.operationType {
    when AFTER_UPDATE {
        // Prescan to bulkify querying for related Accounts
        Set accountIds = new Set();
        for (Opportunity opp : newMap.values()) {
            Opportunity oldOpp = oldMap.get(opp.Id);
            if(opp.AccountId != oldOpp.AccountId) { // AccountId changed?
                accountIds.add(opp.AccountId);
            }
        }                
        // Query related Account records?
        Map associatedAccountsById = accountIds.size()==0 ? 
            new Map() : 
            new Map([select Id, NumberOfEmployees from Account where Id = :accountIds]);
        // Validate
        for (Opportunity opp : newMap.values()) {
            Opportunity oldOpp = oldMap.get(opp.Id);
            if(opp.StageName != oldOpp.StageName) { // Stage changed?
                if(opp.StageName == 'Closed Won') { // Stage closed won?
                    if(opp.Description != oldOpp.Description) { // Description changed?               
                        if(opp.Description == null) { // Description null?
                            opp.Description.addError('Description must be specified when Opportunity is closed');
                        }
                    }
                }                                
            }
            if(opp.AccountId != oldOpp.AccountId) { // AccountId changed?
                Account acct = associatedAccountsById.get(opp.AccountId);
                if(acct!=null) { // Account queried?
                    if(acct.NumberOfEmployees==null) { // NumberOfEmployees null?
                        opp.AccountId.addError('Account does not have any employees');
                    }    
                }
            }
        }
    }
}               

Vous trouverez ci-dessous la même validation mise en œuvre à l’aide d’un cadre conçu pour réduire le code standard.

SObjectFieldValidator.build()            
  .when(TriggerOperation.AFTER_UPDATE)
    .field(Opportunity.Description).hasChanged().isNull().addError('Description must be specified when Opportunity is closed')
      .when(Opportunity.StageName).hasChanged().equals('Closed Won')
    .field(Opportunity.AccountId).whenChanged().addError('Account does not have any employees')
      .when(Account.NumberOfEmployees).isNull()
  .validate(operation, oldMap, newMap);

le SObjectFieldValidator framework utilise le Conception de style fluide à son API et en tant que tel permet au validateur d’être construit dynamiquement avec facilité. De plus, les instances configurées de celui-ci peuvent être transmises et étendues par d’autres chemins de code et modules avec la validation elle-même à effectuer en un seul passage. Le cadre tente également de regrouper les requêtes (dans ce cas, les comptes liés) et de ne le faire que si le champ cible ou les champs associés ont été modifiés, garantissant ainsi un temps de traitement optimal. Le code de test pour l’une ou l’autre des approches peut bien sûr être écrit de la manière habituelle comme indiqué ci-dessous.

// Given
Account relatedAccount = new Account(Name = 'Test', NumberOfEmployees = null);        
insert relatedAccount;
Opportunity opp = new Opportunity(Name = 'Test', CloseDate = Date.today(), StageName = 'Prospecting', Description = 'X', AccountId = null);
insert opp;
opp.StageName = 'Closed Won';
opp.Description = null;
opp.AccountId = relatedAccount.Id;
// When
Database.SaveResult saveResult = Database.update(opp, false);
// Then
List errors = saveResult.getErrors();
System.assertEquals(2, errors.size());
System.assertEquals('Description', errors[0].getFields()[0]);
System.assertEquals('Description must be specified when Opportunity is closed', errors[0].getMessage());
System.assertEquals('AccountId', errors[1].getFields()[0]);
System.assertEquals('Account does not have any employees', errors[1].getMessage());

Bien que vous ayez toujours besoin d’une couverture de code pour votre logique Apex Trigger, ceux qui pratiquent les tests unitaires peuvent préférer tirer parti de la capacité d’éviter le DML afin d’affirmer des scénarios de validation plus variés. Le code suivant est entièrement exempt d’instructions SOQL et DML et donc meilleur pour les performances des tests. Il exploite la possibilité d’injecter des enregistrements associés plutôt que de permettre au framework de les interroger à la demande. L’instance SObjectFieldValidator est construite et configurée dans une classe distincte pour être réutilisée.

// Given
Account relatedAccount = 
    new Account(Id = TEST_ACCOUNT_ID, Name = 'Test', NumberOfEmployees = null);
Map oldMap = 
    new Map { TEST_OPPORTUNIT_ID => 
        new Opportunity(Id = TEST_OPPORTUNIT_ID, StageName = 'Prospecting', Description = 'X', AccountId = null)};
Map newMap = 
    new Map { TEST_OPPORTUNIT_ID => 
        new Opportunity(Id = TEST_OPPORTUNIT_ID, StageName = 'Closed Won', Description = null, AccountId = TEST_ACCOUNT_ID)};
Map> relatedRecords = 
    new Map> {
        Opportunity.AccountId => 
            new Map(new List { relatedAccount })};
// When
OpportunityTriggerHandler.getValidator()
  .validate(TriggerOperation.AFTER_UPDATE, oldMap, newMap, relatedRecords); 
// Then
List errors = newMap.get(TEST_OPPORTUNIT_ID).getErrors();
System.assertEquals(2, errors.size());
System.assertEquals('AccountId', errors[0].getFields()[0]);
System.assertEquals('Account does not have any employees', errors[0].getMessage());
System.assertEquals('Description', errors[1].getFields()[0]);
System.assertEquals('Description must be specified when Opportunity is closed', errors[1].getMessage());

Enfin, il convient de noter qu’un tel cadre ne peut bien sûr vous mener que si loin et qu’il y aura des scénarios où vous devrez être plus riche dans vos critères. C’est quelque chose qui pourrait être approfondi à travers le SObjectFieldValidator.FieldValidationCondition type de base qui permet d’ajouter des validations de champs codés via le état méthode. Le cadre est assez basique car je n’ai vraiment pas beaucoup de temps ces jours-ci pour le construire plus complètement, alors invitez totalement toute personne intéressée à aller plus loin.

Prendre plaisir!



Source de l’article traduit automatiquement en Français

Besoin d'aide ?
Voulez-vous utiliser Pardot à sa capacité maximale et avoir
+ DE LEADS QUALIFIÉS

Notre analyse de votre Pardot offerte dès aujourd'hui
Merci, vous pouvez compléter notre questionnaire
Nous allons revenir vers vous rapidement !

Fermer