Учебники

Apex – триггерные шаблоны проектирования

Шаблоны проектирования используются для того, чтобы сделать наш код более эффективным и избежать ограничения ограничений. Часто разработчики могут написать неэффективный код, который может вызвать повторное создание объектов. Это может привести к неэффективному, плохо работающему коду и, возможно, к нарушению ограничений регулятора. Это чаще всего происходит в триггерах, так как они могут работать с набором записей.

Мы увидим некоторые важные стратегии шаблонов проектирования в этой главе.

Массовые шаблоны дизайна триггеров

В реальном экономическом случае вам может понадобиться обработать тысячи записей за один раз. Если ваш триггер не предназначен для обработки таких ситуаций, он может не работать во время обработки записей. Существует несколько рекомендаций, которым вы должны следовать при реализации триггеров. Все триггеры по умолчанию являются массовыми и могут обрабатывать несколько записей одновременно. Вы всегда должны планировать обрабатывать более одной записи одновременно.

Рассмотрим бизнес-пример, в котором вам нужно обработать большое количество записей, и вы написали триггер, как указано ниже. Это тот же пример, который мы использовали для вставки записи счета-фактуры, когда статус клиента изменяется с неактивного на активный.

// 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
      }
   }
}

Теперь вы можете видеть, что инструкция DML была записана для блока цикла, который будет работать при обработке только нескольких записей, но когда вы обрабатываете несколько сотен записей, он достигнет предела инструкции DML на транзакцию, который является лимитом регулятора . Мы подробно рассмотрим ограничения губернатора в следующей главе.

Чтобы избежать этого, мы должны сделать триггер эффективным для обработки нескольких записей одновременно.

Следующий пример поможет вам понять то же самое –

// 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
}

Этот триггер будет запускать только 1 оператор DML, так как он будет работать над списком, а список содержит все записи, которые необходимо изменить.

Таким образом, вы можете избежать ограничений регулятора операторов DML.

Trigger Helper Class

Написание всего кода в триггере также не является хорошей практикой. Следовательно, вы должны вызвать класс Apex и делегировать обработку от Trigger к классу Apex, как показано ниже. Класс Trigger Helper – это класс, который выполняет всю обработку триггера.

Давайте снова рассмотрим наш пример создания записи счета.

// 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
}

Хелпер Класс

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
   }
}

В этом случае вся обработка была делегирована вспомогательному классу, и когда нам нужна новая функциональность, мы можем просто добавить код в вспомогательный класс без изменения триггера.

Один триггер на каждом объекте

Всегда создавайте один триггер для каждого объекта. Несколько триггеров на одном и том же объекте могут вызвать конфликт и ошибки, если он достигнет ограничений регулятора.

Вы можете использовать контекстную переменную для вызова различных методов из вспомогательного класса согласно требованию. Рассмотрим наш предыдущий пример. Предположим, что наш метод createInvoice должен вызываться только при обновлении записи и при нескольких событиях. Тогда мы можем контролировать выполнение, как показано ниже –