Maps of sObjects
By the end of this lesson, you'll be able to:
- Build a Map<Id, sObject> from a SOQL query result
- Explain why this pattern avoids a second query inside a loop
- Use a Map<Id, sObject> to look up related records efficiently
Prerequisites: "Maps"
Building a Map<Id, sObject> from a query
List<Account> accounts = [SELECT Id, Name, Industry FROM Account];
Map<Id, Account> accountsById = new Map<Id, Account>(accounts);
Id someAccountId = accounts[0].Id;
System.debug(accountsById.get(someAccountId).Name);
List<Account> accounts = [SELECT Id, Name, Industry FROM Account];— a SOQL query returning aList<Account>.Map<Id, Account> accountsById = new Map<Id, Account>(accounts);— passing aList<Account>directly intonew Map<Id, Account>(...)automatically builds a map keyed by each record'sId— no manual loop needed.- (blank line)
Id someAccountId = accounts[0].Id;— grabs one real Id from the query results.System.debug(accountsById.get(someAccountId).Name);— looks it up instantly through the map. This is such a common pattern that Apex has built-in support for it.
The problem this pattern solves
// DON'T DO THIS — a query inside a loop
for (Opportunity opp : opportunities) {
Account acc = [SELECT Name FROM Account WHERE Id = :opp.AccountId]; // a query per iteration!
System.debug(acc.Name);
}
// DON'T DO THIS — a query inside a loop— the label says it all.for (Opportunity opp : opportunities) {— loops over every opportunity.Account acc = [SELECT Name FROM Account WHERE Id = :opp.AccountId];— a separate query runs for every single opportunity.System.debug(acc.Name);— uses the result.}— closes the loop.
Warning: This is exactly the "SOQL-in-a-loop" governor limit problem from Module 7's "Loops and Governor Limits" lesson — line 3 runs a fresh query on every iteration, quickly hitting the 100-query-per-transaction limit with enough opportunities and crashing with a System.LimitException.
The fix: one query, then map lookups
List<Opportunity> opportunities = [SELECT Id, AccountId FROM Opportunity];
Set<Id> accountIds = new Set<Id>();
for (Opportunity opp : opportunities) {
accountIds.add(opp.AccountId);
}
Map<Id, Account> accountsById = new Map<Id, Account>(
[SELECT Id, Name FROM Account WHERE Id IN :accountIds]
);
for (Opportunity opp : opportunities) {
Account relatedAccount = accountsById.get(opp.AccountId);
System.debug(relatedAccount.Name);
}
List<Opportunity> opportunities = [SELECT Id, AccountId FROM Opportunity];— one query, run once.- (blank line)
Set<Id> accountIds = new Set<Id>();— aSetto collect unique Account Ids, deduplicating automatically (this module's first lesson).for (Opportunity opp : opportunities) {— loops over the opportunities already in memory — no querying here.accountIds.add(opp.AccountId);— collects the id, duplicates silently ignored.}— closes the loop.- (blank line)
Map<Id, Account> accountsById = new Map<Id, Account>(— builds a lookup map...[SELECT Id, Name FROM Account WHERE Id IN :accountIds]— ...from a second query, but only ever one, fetching exactly the needed Accounts.);— closes the constructor call.- (blank line)
for (Opportunity opp : opportunities) {— loops again over the same in-memory list.Account relatedAccount = accountsById.get(opp.AccountId);— an instant map lookup, no query.System.debug(relatedAccount.Name);— uses the result.}— closes the loop.
One query collects the needed Account Ids, one query fetches those Accounts, and the Map makes every subsequent lookup instant — regardless of how many opportunities there are. This exact pattern reappears constantly in later modules on triggers and bulkification.
Exercise
Given List<Contact> contacts (each with an Id and Name), build a Map<Id, Contact> keyed by Id using the constructor shortcut.
Show hint
new Map<Id, Contact>(contacts)
Maps of sObjects 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
Map<Id, sObject> is the single most common Map shape in real Apex code — it lets you look up a Salesforce record by its Id in memory, entirely avoiding a second SOQL query inside a loop.