The Map class is probably the most useful collection on the Salesforce platform.
When you combine a Map with a SOQL query you have a really cool tool for automatically populutating a Map of SObjects keyed on Id using a special Map constructor:
Map<Id, Account> accountMap = new Map<Id, Account>([Select Id, Name From Account]);
This is well documented (and really useful for bulk loading foreign objects in triggers) but it turns out you can use this map constructor to populate a Map from any list of SObjects.
In the following example we have a query that loads Accounts as well as Opportunities. You can use the Map constructor to load the subquery results into a Map as follows:
// Query Accounts and Opportunities into a Map Map<Id, Account> accountMap = new Map<Id, Account>([Select Id, Name, (Select Id, Name From Opportunities) From Account]); // Iterate over the Map keys for (Id key : accountMap.keySet()) { Account acc = accountMap.get(key); System.debug('Account: ' + key + ' => ' + acc.Name); // Load the Opportunities into a Map Map<Id, Opportunity> oppMap = new Map<Id, Opportunity>(acc.Opportunities); // Iterate over the Map Keys for (Id key2 : oppMap.keySet()) { Opportunity opp = oppMap.get(key2); System.debug('Opportunity: ' + key2 + ' => ' + opp.Name); } }
You can do the same with Dynamic SOQL with one subtle difference, you need to check for Nulls:
// Query to execute String query = 'Select Id, Name, (Select Id, Name From Opportunities) From Account'; // Query Accounts and Opportunities into a Map Map<Id, SObject> sObjectMap = new Map<Id, SObject>(Database.query(query)); // Iterate over the Map keys for (Id key : sObjectMap.keySet()) { SObject so = sObjectMap.get(key); System.debug('Account SObject: ' + key + ' => ' + so.get('Name')); // Load the Opportunities into a Map List<SObject> sos = so.getSObjects('Opportunities'); // Check the Map for Null in case the Account has no Opportunities if (sos != null) { Map<Id, SObject> soMap2 = new Map<Id, SObject>(); // Iterate over the Map keys for (Id key2 : soMap2.keySet()) { SObject so2 = soMap2.get(key2); System.debug('Opportunity SObject: ' + key2 + ' => ' + so2.get('Name')); } } }
The Map constructor also allows you to use a Dynamic SOQL query to load into Map of concrete SOBjects by casting it to a List:
String query = 'Select Id, Name From Account'; Map<Id, Account> accountMap = new Map<Id, Account>((List<Account>)Database.query(query));
A Final Word of Warning:
Always exercise caution when using undocumented features within Salesforce. They may break without warning.