Programming Techniques

Apex Supplemental Documentation

Contents

Manually Adding Records to a List

If you need to create a List Collection of records on-the-fly, use the add and the new methods.

Contact[] testContacts = new List<Contact>();
testContacts.add(new Contact(FirstName = 'John', LastName = 'Doe'));
testContacts.add(new Contact(FirstName = 'Mary', LastName = 'Smith'));


You'll probably use this most often when creating dummy data for unit tests.

Creating a Set of Unique IDs

You can use a for loop to create a Set of unique IDs from a group of records. This is helpful when you have a group of child records and want to extract the master record IDs.

For example, let's say that Trigger.new contains a large number of Contact records and you want to create a Set of unique Account IDs from it.

Set<Id> acctIDs = new Set<Id>();
for (Contact person: Trigger.new) {
  acctIDs.add(person.AccountID);
}


As you loop through the group of Contacts, any duplicate Account IDs will be omitted from the Set as it is created.

Using A Map as a SOQL select filter

You can use a map to “expose” the IDs of a group of records so that they can be used as as filter for a SOQL select on a different type of record.

For example, let's say Trigger.new contains a group of Account records and you want to retrieve all the Contact records belonging to those accounts.

You can create a map called “contactAccount” in a single statement:

Map<Id, Account> contactAccount = new Map<ID, Account>(Trigger.new);


This statement places the Account ID in the key field and the Account record in the value field of the Map.

Now you can retrieve all the Contacts at once in a single SOQL command:

Contact[] people = new List<Contact>(); people = [select Id, AccountId, MailingCity, MailingState from Contact where AccountId in : contactAccount.keySet()];


Notice the use of the keySet method to provide the IDs for the where clause.


Referencing Field Values in a Map's Records

You can reference the field values of the records in a map. Let's say Trigger.new contains a group of Account records:

Map<Id, Account> contactAccount = new Map<ID, Account>(Trigger.new);


Set a variable that contains an ID of one of the accounts in the map:

Id testID = '00300000003T2PGAA0';


Now you can reference the record's field values in this way:

String var1 = contactAccount.get(testID).BillingStreet;
String var2 = contactAccount.get(testID).BillingCity;


You can think of the contactAccount.get(testID) method as returning an sObject (an account record), at which point you can refer to the fields easily by the sObject.fieldname functionality. See page 27-28 in the Apex Language Reference.

Using Nested SOQL Statements

You can use a nested SOQL statement to retrieve detail records at the same time as the master record is being retrieved. You do not need to declare a List Collection to contain the child records – they are automatically created and linked to the master records' List Collection.

Notice that the nested select statement uses the Plural Label of the child object, not the singular.

For example: Say you have a Set of Account IDs and you wish to retrieve the Account Name and Billing Address of each account, and the Amounts and Close Dates of all Opportunities for each account.

Account[] accts = new List<Account>();
Set<Id> acctIDs = new Set<Id>();

// ...
// Imagine some code here that populates the AcctIDs Set.
// ...
accts = [select Id, Name, BillingAddress, (select Amount, CloseDate from Opportunities) from Account where ID in :acctIDs];


The result is that accts.Opportunities will contain all the Opportunity records for each Account.

If the child table is a custom object, then you must use the Plural Label name of the object, remove any spaces, and add "__r" to the name. This is instead of using the standard object name. Image:ChildObjectLabel.jpg


For example: Say you have a custom object called Membership_Payment__c that is a child of Contact. If you wish to retrieve the First Name, Last Name, and Amounts of all Membership Payments for each contact:

Contact[] people = new List<Contact>();
Set<Id> contactIDs = new Set<Id>();
// ...
// Imagine some code here that populates the contactIDs Set.
// ...
people = [select Id, FirstName, LastName, (select Amount from MembershipPayments__r) from Contact where ID in :contactIDs];


The result is that people.Opportunities will contain all the Opportunity records for each Account.

www.salesforce.com/us/developer/docs/api/index_CSH.htm#sforce_api_calls_soql.htm.

Using a Map as an In-Memory Join Table

You can build in-memory join tables when you need to manipulate master-detail data. It is far more efficient to use Maps than to perform a select statement for each master record and its details. This is important due to the limits on total number of SOQL executions performed in an Apex script.

For example: let's construct a join table of Accounts and Opportunities. First, we'll use a nested SOQL statement to retrieve all the data at once:

Account[] accts = new List<Account>();
Set<Id> acctIDs = new Set<Id>();
// ...
//Imagine some code here that populates the AcctIDs Set.
// ...
accts = [select Id, Name, BillingAddress, (select Amount, CloseDate from Opportunities) from Account where ID in :acctIDs];


Then we'll build a Map using the Account ID as the key and a List Collection of Opportunity records as the values.

Map<Id, Opportunity []> acctOpps = new Map<Id, Opportunity[]>();
for (Account eachAcct: accts) {
  acctOpps.put(eachAcct.Id, eachAcct.Opportunities);
}


Now, when you use loops to read through the Map, it is all in memory. This is far more efficient than retrieving the data one account at a time:

Opportunity[] opps = new List< Opportunity>();
for (Account eachAcct: accts) {
  opps = acctOpps.get(eachAcct.Id);
  //...
  //code here whatever data manipulation you are attempting.
}


Note that if a custom object is the child object, then you use __c when declaring the Map object but use __r when assigning the map value.

Map<Id, Membership_Payment__c[]> contactPayments = new Map<Id, Membership_Payment__c[]>();
for (Contact person : people) {
  contactPayments.put(person.Id, person.Membership_Payments__r);
}

Creating a “Reverse” Map

A map typically consists of an ID as the key and a string value as the value. However, there may be times when you want to reverse the roles and look up an ID based on a string.

For example: say you want to look up the Record Type ID of a Contact record type named “Media.”

Map<String, Id> recTypesRev = new Map<String, Id>();
//Build a "reversed" map so that the record type name becomes the Key and the id is the Value.
for(RecordType rec :[select id, name from RecordType
where sObjectType = 'Contact') {
  recTypesRev.put(rec.Name, rec.Id);
}
Id mediaTypeID = recTypesRev.get('Media');