[Salesforce] Apex Triggers - Bulk Apex Triggers



Get Started with Apex Triggers

https://trailhead.salesforce.com/content/learn/modules/apex_triggers/apex_triggers_bulk


Bulk Trigger Design Patterns

사용 시 장점

  • 트리거 성능 향상
  • 서버 리소스 사용량 줄어듦
  • 플랫폼 제한 초과 가능성 낮아짐
  • 멀티테넌트 플랫폼에서 코드가 리소스를 독점하는 현상을 방지


레코드셋 작업하기

trigger MyTriggerBulk on Account(before insert) {
    for(Account a : Trigger.new) {
        a.Description = 'New description';
    }
}


Bulk SOQL 수행하기

trigger SoqlTriggerBulk on Account(after update) {
    // Perform SOQL query once.
    // Get the accounts and their related opportunities.
    List<Account> acctsWithOpps =
        [SELECT Id,(SELECT Id,Name,CloseDate FROM Opportunities)
         FROM Account WHERE Id IN :Trigger.new];
    // Iterate over the returned accounts
    for(Account a : acctsWithOpps) {
        Opportunity[] relatedOpps = a.Opportunities;
        // Do some other processing
    }
}
  • 내부쿼리 (SELECT Id,Name,CloseDate FROM Opportunities)를 사용해서 Opportunities를 가져옴
  • IN을 통해 trigger context 바인딩 가능


trigger SoqlTriggerBulk on Account(after update) {
    // Perform SOQL query once.
    // Get the related opportunities for the accounts in this trigger.
    List<Opportunity> relatedOpps = [SELECT Id,Name,CloseDate FROM Opportunity
        WHERE AccountId IN :Trigger.new];
    // Iterate over the related opportunities
    for(Opportunity opp : relatedOpps) {
        // Do some other processing
    }
}
  • 상위레코드(Account)가 필요하지 않으면 이렇게도 사용 가능




대량 DML 수행하기

trigger DmlTriggerBulk on Account(after update) {
    // Get the related opportunities for the accounts in this trigger.
    List<Opportunity> relatedOpps = [SELECT Id,Name,Probability FROM Opportunity
        WHERE AccountId IN :Trigger.new];
    List<Opportunity> oppsToUpdate = new List<Opportunity>();
    // Iterate over the related opportunities
    for(Opportunity opp : relatedOpps) {
        // Update the description when probability is greater
        // than 50% but less than 100%
        if ((opp.Probability >= 50) && (opp.Probability < 100)) {
            opp.Description = 'New description for opportunity.';
            oppsToUpdate.add(opp);
        }
    }
    // Perform DML on a collection
    update oppsToUpdate;
}
  • oppsToUpdate 리스트에 DML 수행 대상 추가

Bulk Design Pattern - 관련 레코드 조회 예시

trigger AddRelatedRecord on Account(after insert, after update) {
    List<Opportunity> oppList = new List<Opportunity>();
    // Add an opportunity for each account if it doesn't already have one.
    // Iterate over accounts that are in this trigger but that don't have opportunities.
    List<Account> toProcess = null;
    switch on Trigger.operationType {
        when AFTER_INSERT {
        // All inserted Accounts will need the Opportunity, so there is no need to perform the query
            toProcess = Trigger.New;
        }
        when AFTER_UPDATE {
            toProcess = [SELECT Id,Name FROM Account
                         WHERE Id IN :Trigger.New AND
                         Id NOT IN (SELECT AccountId FROM Opportunity WHERE AccountId in :Trigger.New)];
        }
    }
    for (Account a : toProcess) {
        // Add a default opportunity for this account
        oppList.add(new Opportunity(Name=a.Name + ' Opportunity',
                                    StageName='Prospecting',
                                    CloseDate=System.today().addMonths(1),
                                    AccountId=a.Id));
    }
    if (oppList.size() > 0) {
        insert oppList;
    }
}
  • switch 문을 사용해서 각 Operation Type 별 처리 나눔


  • Opportunity까지 생성 확인




Hands-on

  • Opportunity에 대해서 Stage가 Closed Won일 때 follow-up task 추가하기
trigger ClosedOpportunityTrigger on Opportunity (after insert, after update) {
    
    // Get the related opportunities for the accounts in this trigger.
    List<Opportunity> opps = [SELECT Id,Name,StageName
                              FROM Opportunity
                              WHERE Id IN :Trigger.new];
    
    List<Task> tasksToUpdate = new List<Task>();
    // Iterate over the related opportunities
    for(Opportunity opp : opps) {
        if (opp.StageName == 'Closed Won') {
            Task task = new Task();
            task.Subject = 'Follow Up Test Task';
            task.WhatId = opp.Id;
            tasksToUpdate.add(task);
        }
    }
    // Perform DML on a collection
    upsert tasksToUpdate;

}

다른 글