Apex - Modèles de conception de déclenchement

Les modèles de conception sont utilisés pour rendre notre code plus efficace et pour éviter d'atteindre les limites du gouverneur. Les développeurs peuvent souvent écrire du code inefficace qui peut provoquer une instanciation répétée des objets. Cela peut entraîner un code inefficace et peu performant, et potentiellement la violation des limites du gouverneur. Cela se produit le plus souvent dans les déclencheurs, car ils peuvent fonctionner sur un ensemble d'enregistrements.

Nous verrons quelques stratégies de design pattern importantes dans ce chapitre.

Modèles de conception de déclencheurs en masse

Dans une analyse de rentabilisation réelle, il est possible que vous deviez traiter des milliers d'enregistrements en une seule fois. Si votre déclencheur n'est pas conçu pour gérer de telles situations, il peut échouer lors du traitement des enregistrements. Vous devez suivre certaines bonnes pratiques lors de la mise en œuvre des déclencheurs. Tous les déclencheurs sont des déclencheurs en bloc par défaut et peuvent traiter plusieurs enregistrements à la fois. Vous devez toujours prévoir de traiter plus d'un enregistrement à la fois.

Prenons une analyse de rentabilisation dans laquelle vous devez traiter un grand nombre d'enregistrements et vous avez écrit le déclencheur comme indiqué ci-dessous. C'est le même exemple que nous avions pris pour insérer l'enregistrement de facture lorsque le statut du client passe de Inactif à Actif.

// Bad Trigger Example
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   
   for (APEX_Customer__c objCustomer: Trigger.new) {
      
      if (objCustomer.APEX_Customer_Status__c == 'Active' && 
         trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
         
         // condition to check the old value and new value
         APEX_Invoice__c objInvoice = new APEX_Invoice__c();
         objInvoice.APEX_Status__c = 'Pending';
         insert objInvoice;   //DML to insert the Invoice List in SFDC
      }
   }
}

Vous pouvez maintenant voir que l'instruction DML a été écrite pour le bloc de boucle qui fonctionnera lors du traitement de quelques enregistrements seulement, mais lorsque vous traitez des centaines d'enregistrements, elle atteindra la limite de l'instruction DML par transaction qui est le governor limit. Nous examinerons en détail les limites du gouverneur dans un chapitre suivant.

Pour éviter cela, nous devons rendre le déclencheur efficace pour traiter plusieurs enregistrements à la fois.

L'exemple suivant vous aidera à comprendre la même chose -

// Modified Trigger Code-Bulk Trigger
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();
   
   for (APEX_Customer__c objCustomer: Trigger.new) {
      
      if (objCustomer.APEX_Customer_Status__c == 'Active' &&
         trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
         
         //condition to check the old value and new value
         APEX_Invoice__c objInvoice = new APEX_Invoice__c();
         objInvoice.APEX_Status__c = 'Pending';
         InvoiceList.add(objInvoice);//Adding records to List
      }
   }
   
   insert InvoiceList;
   // DML to insert the Invoice List in SFDC, this list contains the all records 
   // which need to be modified and will fire only one DML
}

Ce déclencheur ne déclenchera qu'une seule instruction DML car il fonctionnera sur une liste et la liste contient tous les enregistrements qui doivent être modifiés.

De cette manière, vous pouvez éviter les limites du gouverneur d'instruction DML.

Classe d'aide au déclenchement

Ecrire tout le code dans trigger n'est pas non plus une bonne pratique. Par conséquent, vous devez appeler la classe Apex et déléguer le traitement de Trigger à la classe Apex comme indiqué ci-dessous. La classe Trigger Helper est la classe qui effectue tout le traitement du déclencheur.

Considérons à nouveau notre exemple de création d'enregistrement de facture.

// Below is the Trigger without Helper class
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();
   
   for (APEX_Customer__c objCustomer: Trigger.new) {
      
      if (objCustomer.APEX_Customer_Status__c == 'Active' &&
         trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
         
         // condition to check the old value and new value
         APEX_Invoice__c objInvoice = new APEX_Invoice__c();
         objInvoice.APEX_Status__c = 'Pending';
         InvoiceList.add(objInvoice);
      }
   }
   
   insert InvoiceList; // DML to insert the Invoice List in SFDC
}

// Below is the trigger with helper class
// Trigger with Helper Class
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   CustomerTriggerHelper.createInvoiceRecords(Trigger.new, trigger.oldMap);
   // Trigger calls the helper class and does not have any code in Trigger
}

Classe d'assistance

public class CustomerTriggerHelper {
   public static void createInvoiceRecords (List<apex_customer__c>
   
   customerList, Map<id, apex_customer__c> oldMapCustomer) {
      List<apex_invoice__c> InvoiceList = new Listvapex_invoice__c>();
      
      for (APEX_Customer__c objCustomer: customerList) {
         
         if (objCustomer.APEX_Customer_Status__c == 'Active' &&
            oldMapCustomer.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
            
            // condition to check the old value and new value
            APEX_Invoice__c objInvoice = new APEX_Invoice__c();
            
            // objInvoice.APEX_Status__c = 'Pending';
            InvoiceList.add(objInvoice);
         }
      }
      
      insert InvoiceList;  // DML to insert the Invoice List in SFDC
   }
}

En cela, tout le traitement a été délégué à la classe d'assistance et lorsque nous avons besoin d'une nouvelle fonctionnalité, nous pouvons simplement ajouter le code à la classe d'assistance sans modifier le déclencheur.

Déclencheur unique sur chaque sObject

Créez toujours un seul déclencheur sur chaque objet. Plusieurs déclencheurs sur le même objet peuvent provoquer le conflit et des erreurs s'il atteint les limites du gouverneur.

Vous pouvez utiliser la variable de contexte pour appeler les différentes méthodes de la classe d'assistance selon l'exigence. Prenons notre exemple précédent. Supposons que notre méthode createInvoice ne doit être appelée que lorsque l'enregistrement est mis à jour et sur plusieurs événements. Ensuite, nous pouvons contrôler l'exécution comme ci-dessous -

// Trigger with Context variable for controlling the calling flow
trigger Customer_After_Insert on APEX_Customer__c (after update, after insert) {
   
   if (trigger.isAfter && trigger.isUpdate) {
      // This condition will check for trigger events using isAfter and isUpdate
      // context variable
      CustomerTriggerHelper.createInvoiceRecords(Trigger.new);
      
      // Trigger calls the helper class and does not have any code in Trigger
      // and this will be called only when trigger ids after update
   }
}

// Helper Class
public class CustomerTriggerHelper {
   
   //Method To Create Invoice Records
   public static void createInvoiceRecords (List<apex_customer__c> customerList) {
      
      for (APEX_Customer__c objCustomer: customerList) {
         
         if (objCustomer.APEX_Customer_Status__c == 'Active' &&
            trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
            
            // condition to check the old value and new value
            APEX_Invoice__c objInvoice = new APEX_Invoice__c();
            objInvoice.APEX_Status__c = 'Pending';
            InvoiceList.add(objInvoice);
         }
      }
      
      insert InvoiceList; // DML to insert the Invoice List in SFDC
   }
}