Bulkify the Logic
By the end of this lesson, you'll be able to:
- Collect the Account Id and Amount delta for every affected Opportunity
- Query and update the affected Accounts in a single bulk operation
- Apply Module 25's "collect, then act once" pattern to this specific feature
Prerequisites: "Build the Trigger Handler"
Collecting the amount to adjust, per Account
public void afterUpdate(List<Opportunity> newOpportunities, Map<Id, Opportunity> oldMap) {
Map<Id, Decimal> amountAdjustmentByAccountId = new Map<Id, Decimal>();
for (Opportunity opp : newOpportunities) {
Opportunity oldOpp = oldMap.get(opp.Id);
Boolean justWon = opp.StageName == 'Closed Won' && oldOpp.StageName != 'Closed Won';
Boolean justUnwon = opp.StageName != 'Closed Won' && oldOpp.StageName == 'Closed Won';
Decimal amount = opp.Amount == null ? 0 : opp.Amount;
if (justWon) {
addAdjustment(amountAdjustmentByAccountId, opp.AccountId, amount);
} else if (justUnwon) {
addAdjustment(amountAdjustmentByAccountId, opp.AccountId, -amount);
}
}
// ... apply the adjustments (next section)
}
private void addAdjustment(Map<Id, Decimal> adjustments, Id accountId, Decimal amount) {
if (! adjustments.containsKey(accountId)) {
adjustments.put(accountId, 0);
}
adjustments.put(accountId, adjustments.get(accountId) + amount);
}
This is Module 16's "Maps of sObjects" pattern combined with Module 6's ternary operator (defaulting a null Amount to 0) — one entry per affected Account, even if several Opportunities for the same Account changed in this one transaction.
Applying the adjustments in one bulk update
private void applyAdjustments(Map<Id, Decimal> amountAdjustmentByAccountId) {
if (amountAdjustmentByAccountId.isEmpty()) {
return;
}
List<Account> accounts = [
SELECT Id, Total_Won_Revenue__c
FROM Account
WHERE Id IN :amountAdjustmentByAccountId.keySet()
];
for (Account acc : accounts) {
Decimal current = acc.Total_Won_Revenue__c == null ? 0 : acc.Total_Won_Revenue__c;
acc.Total_Won_Revenue__c = current + amountAdjustmentByAccountId.get(acc.Id);
}
update accounts;
}
This is Module 25's core pattern applied directly: one query (WHERE Id IN :...keySet(), Module 16's keySet()) and one update, regardless of whether 1 or 200 Opportunities changed in this transaction — exactly what makes this feature bulk-safe.
Exercise
As a comment, explain why amountAdjustmentByAccountId.isEmpty() is checked before running the query and update.
Show hint
Think about a batch of Opportunity updates where none of them actually changed Closed Won status.
Bulkify the Logic Quiz
My Notes
Log in to keep private notes on this lesson.
Questions about this lesson
No questions yet — be the first to ask.
Log in to ask a question about this lesson.
Summary
This lesson turns the previous lesson's per-record debug statements into a real, bulk-safe rollup — querying and updating Accounts once, regardless of how many Opportunities changed.