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 语句已写入 for 循环块,该循环块在仅处理少数记录时可以工作,但当您处理数百条记录时,它将达到每个事务的 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 语句调控器的限制。

触发辅助类

在触发器中编写整个代码也不是一个好的做法。因此,您应该调用 Apex 类并将处理从 Trigger 委托给 Apex 类,如下所示。触发器助手类是对触发器进行所有处理的类。

让我们再次考虑发票记录创建示例。

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

在这种情况下,所有处理都已委托给帮助程序类,当我们需要新功能时,我们可以简单地将代码添加到帮助程序类,而无需修改触发器。

每个 sObject 上的单次触发器

始终在每个对象上创建一个触发器。如果达到调控器限制,同一对象上的多个触发器可能会导致冲突和错误。

您可以根据需要使用上下文变量从帮助器类中调用不同的方法。考虑我们前面的例子。假设我们的 createInvoice 方法应该仅在记录更新且发生多个事件时调用。然后我们可以控制执行如下 -

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