Fix a query inside a loop
Debug it · Intermediate · 15 min · Runs in your Salesforce Developer org · Apex Path
Scenario. Support imports 200 Contacts every Monday. The import has failed with Too many SOQL queries: 101 since a new trigger went live.
A Contact trigger looks up each Account one at a time. It passes every test with 5 records and dies on a 200-record import. Bulkify it.
What you will learn
Too many SOQL queries: 101 is the classic production failure. The code is right for one record: one query per record. An import of 200 needs 200 queries, twice the limit of 100.
The fix is always three steps: collect the Ids, run one query into a Map, look each record up in the loop.
Map<Id, Account> byId = new Map<Id, Account>([
SELECT Name FROM Account WHERE Id IN :accountIds
]);
Gotcha. Collecting Ids and using them are two loops. The query sits between them.
The task
Fix the handler so it runs at most one query however many Contacts are inserted, and still stamps each Contact with its Account's name.
Examples:
- Contact on Account
Acme→ DescriptionWorks at Acme - Contact with no Account → Description stays as it was
- 200 Contacts on 200 different Accounts → all stamped, one query
Requirements:
- Collect the AccountIds of the Contacts first, skipping blanks.
- Run one query for all of them into a
Map<Id, Account>. - In a second loop, set Description to
Works atfollowed by the Account's Name. - Leave Contacts with no Account, or an Account the query did not return, unchanged.
Starter code
public class AS_A9DF0520ABDF_AccountStamp {
public static void beforeInsert(List<Contact> contacts) {
for (Contact contact : contacts) {
if (contact.AccountId == null) {
continue;
}
Account account = [
SELECT Name
FROM Account
WHERE Id = :contact.AccountId
];
contact.Description = 'Works at ' + account.Name;
}
}
}
When it passes
Every Contact with an Account is stamped with its Account's name. The whole insert costs one query, for 2 Contacts or 200.
You write the Apex yourself. ApexSensei runs it and tells you what passed and what did not.