[Salesforce] Apex Triggers - Bulk Apex Triggers
2026, May 02
목차
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;
}