Apex - 触发器设计模式
设计模式用于使我们的代码更加高效并避免达到调控器限制。 开发人员通常会编写低效的代码,从而导致对象的重复实例化。 这可能会导致代码效率低下、性能不佳,并可能违反调控器限制。 这最常发生在触发器中,因为它们可以针对一组记录进行操作。
我们将在本章中看到一些重要的设计模式策略。
批量触发器设计模式
在实际业务案例中,您可能需要一次性处理数千条记录。 如果您的触发器不是为处理此类情况而设计的,那么它在处理记录时可能会失败。 实施触发器时需要遵循一些最佳实践。 所有触发器默认都是批量触发器,并且可以一次处理多条记录。 您应该始终计划一次处理多个记录。
考虑一个业务案例,其中,您需要处理大量记录,并且您已经编写了如下所示的触发器。 这与我们在客户状态从非活动状态更改为活动状态时插入账单记录的示例相同。
// 错误触发示例 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') { // 检查旧值和新值的条件 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 语句限制,即调控器限制。 我们将在后续章节中详细介绍调控器限制。
为了避免这种情况,我们必须使触发器能够高效地一次处理多个记录。
下面的例子将帮助您理解相同的内容 −
// 修改触发代码-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') { //检查旧值和新值的条件 APEX_Invoice__c objInvoice = new APEX_Invoice__c(); objInvoice.APEX_Status__c = 'Pending'; InvoiceList.add(objInvoice);//Adding records to List } } insert InvoiceList; // DML 在 SFDC 中插入账单列表,该列表包含所有记录 // 需要修改并且只会触发一个 DML }
此触发器将仅触发 1 个 DML 语句,因为它将对列表进行操作,并且该列表包含需要修改的所有记录。
通过这种方式,您可以避免 DML 语句调控器的限制。
触发辅助类
在触发器中编写整个代码也不是一个好的做法。 因此,您应该调用 Apex 类并将处理从 Trigger 委托给 Apex 类,如下所示。 Trigger Helper类是对触发器进行所有处理的类。
让我们再次考虑账单记录创建示例。
// 下面是没有 Helper 类的触发器 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') { // 检查旧值和新值的条件 APEX_Invoice__c objInvoice = new APEX_Invoice__c(); objInvoice.APEX_Status__c = 'Pending'; InvoiceList.add(objInvoice); } } insert InvoiceList; // 在 SFDC 中插入账单列表的 DML } // 下面是带有辅助类的触发器 // 使用辅助类触发 trigger Customer_After_Insert on APEX_Customer__c (after update) { CustomerTriggerHelper.createInvoiceRecords(Trigger.new, trigger.oldMap); // Trigger调用辅助类,并且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') { // 检查旧值和新值的条件 APEX_Invoice__c objInvoice = new APEX_Invoice__c(); // objInvoice.APEX_Status__c = 'Pending'; InvoiceList.add(objInvoice); } } insert InvoiceList; // 在 SFDC 中插入账单列表的 DML } }
在这种情况下,所有处理都已委托给辅助类,当我们需要新功能时,我们可以简单地将代码添加到辅助类中,而无需修改触发器。
每个 sObject 上的单个触发器
始终在每个对象上创建一个触发器。 如果达到调控器限制,同一对象上的多个触发器可能会导致冲突和错误。
您可以根据需要使用上下文变量从帮助器类中调用不同的方法。 考虑我们前面的例子。 假设我们的 createInvoice 方法应该仅在记录更新且发生多个事件时调用。 然后我们可以如下控制执行 −
// 使用上下文变量触发以控制调用流程 trigger Customer_After_Insert on APEX_Customer__c (after update, after insert) { if (trigger.isAfter && trigger.isUpdate) { // 此条件将使用 isAfter 和 isUpdate 检查触发事件 // 上下文变量 CustomerTriggerHelper.createInvoiceRecords(Trigger.new); // Trigger调用辅助类并且Trigger中没有任何代码 // 仅当更新后触发 ids 时才会调用此函数 } } // 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 } }