Best Practice: Bulkify Your Code

Short Description of Advice

Ensure that your code can properly process more than one record at a time.

Motivation for Advice

Code that has been bulkified (structured to handle processing of multiple records) will run properly in different contexts. In particular, if you import data, the trigger or method that ordinarily only receives a single record as input, will receive a hundred - to run correctly in this context (and others) it should be written to handle multiple records.

Explanation

The term bulkifying Apex code refers to the concept of making sure the code properly handles more than one record at a time. When a batch of records initiate Apex, a single instance of that Apex code is executed, but it needs to handle all of the records in that given batch. For example, a trigger could be invoked by an Force.com Web Services API call that inserted a batch of records. Or a custom Apex Web Service. So if a batch of records invokes the the same Apex code, all of those records need to be processed as a bulk, in order to write scalable code and avoid hitting governor limits.

Here is an example of poorly written code that only handles one record:

trigger accountTestTrggr on Account (before insert, before update) {

   //This only handles the first record in the Trigger.new collection
   //But if more than 1 Account initiated this trigger, those additional records
   //will not be processed
   Account acct = Trigger.new[0];
   List<Contact> contacts = [select id, salutation, firstname, lastname, email 
              from Contact where accountId = :acct.Id];
   
}

The issue is that only one Account record is handled because the code explicitly accesses only the first record in the Trigger.new collection by using the syntax Trigger.new[0]. Instead, the trigger should properly handle the entire collection of Accounts in the Trigger.new collection.

Here is a sample of how to handle all incoming records:

trigger accountTestTrggr on Account (before insert, before update) {

   List<String> accountNames = new List<String>{};
 
   //Loop through all records in the Trigger.new collection
   for(Account a: Trigger.new){
      //Concatenate the Name and billingState into the Description field
      a.Description = a.Name + ':' + a.BillingState
   }
   
}

Notice how this revised version of the code iterates across the entire Trigger.new collection with a for loop. Now if this trigger is invoked with a single Account or up to 200 Accounts, all records will be properly processed.

Resources

  • See the Apex Technical Library page for a comprehensive list of resources about Apex Code.
  • See the Database Services Technical Library page for a comprehensive list of resources about the database.
  • See the Apex Developer's Guide to learn about Apex Code.

Author: Andrew Albert (2009-07-16)

Categories: Logic, Database