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 문 한도에 도달합니다. governor limit. 다음 장에서 주지사 제한에 대해 자세히 살펴볼 것입니다.
이를 방지하려면 한 번에 여러 레코드를 처리하기 위해 트리거를 효율적으로 만들어야합니다.
다음 예는 동일한 내용을 이해하는 데 도움이됩니다.
// 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 클래스로 처리를 위임해야합니다. 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
}
}
여기에서 모든 처리는 도우미 클래스에 위임되었으며 새 기능이 필요할 때 트리거를 수정하지 않고 도우미 클래스에 코드를 추가하기 만하면됩니다.
각 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
}
}