1. Bulkified Triggers:

Bulkifying triggers means writing apex triggers using bulk design pattern so that triggers have better performance and consume less server resources.

As a result of it bulkified code can process large number of records efficiently and run within governor limits on force.com platform.

The main characteristics of bulkified code is:

  1. Operating on all records of trigger.
  2. Performing SOQL & DML on collections of sObjects instead of single sObject at a time.
  3. Using maps to hold query results organized by record id. Avoid query within a query and save records in map which later can be accessed through map rather than using SOQL.
  4. Using Sets to isolate distinct records.

trigger ApexTrigger on Lead (before insert) 

{

    /**** Bulkified Triggers ****/

    Lead l = Trigger.new[0]; // will only update the value for first record

    l.Rating = ‘Warm’; //Avoid using Triggers like this

    //Always use Triggers in Bulkified form

    for(Lead l : Trigger.new) // will iterate through all the new records

    { 

        l.Rating = ‘Warm’;

    }

}

Bulkified Triggers – Coding practices:

Example 1:

Avoid creating Triggers that work only for individual records but not for entire datasets:

trigger testTrigger on Acount__c (before insert) {

Acount__c acc = Trigger.New[0]; 

acc.Address__c = ‘Temporary Address’;

}

Create Triggers that use loops to help iterate over a list of records within a transaction:

trigger testTrigger on Acount__c (before insert) {

    integer i = 1;

    for(Acount__c acc : Trigger.new){ 

acc.Address__c = ‘Test Address ‘+i;

        i++;

}

}

Example 2:

In this code, let’s assume 200 Account records are updated, so the “for” loop would iterate over 200 records.

trigger BranchTrigger on Branch__c (before update) {

    for(Branch__c br : Trigger.new){ 

List<Acount__c> accList = [SELECT Name, Account_Name__c, Address__c, 

Balance__c FROM Acount__c 

WHERE Acount_of_Branch__c = :br.id]; 

System.debug(accList);

         // Perform specified logic with queried records

}

}

Now let’s look at a good example of querying bulk data and iterating it.

trigger BranchTrigger on Branch__c (before update) {

    List<Acount__c> accList = [SELECT Name, Account_Name__c, Address__c, 

Balance__c FROM Acount__c 

WHERE Acount_of_Branch__c IN :Trigger.New];

System.debug(accList);

    for(Acount__c acc : accList){ 

         // Perform specified logic with queried records

}

}

Example 3:

DML statements are also bound by Governor Limits; you can call only 150 DML operations in a transaction.

trigger BranchTrigger on Branch__c (before update) {

    List<Acount__c> accList = [SELECT Name, Account_Name__c, Address__c, 

Balance__c FROM Acount__c 

WHERE Acount_of_Branch__c IN :Trigger.New];

System.debug(accList);

    integer i = 0;

    for(Acount__c acc : accList){ 

        acc.Address__c = ‘Test Address ‘+i;

        i++;

        update acc;

}

}

Let’s look a correct coding example where we have instantiated another Account object list called “accToUpdate.”

trigger BranchTrigger on Branch__c (before update) {

      List<Acount__c> accToUpdate = new List<Acount__c>();

List<Acount__c> accList = [SELECT Name, Account_Name__c, Address__c, 

Balance__c FROM Acount__c 

WHERE Acount_of_Branch__c IN :Trigger.New];

System.debug(accList);

    integer i = 0;

    for(Acount__c acc : accList){ 

        acc.Address__c = ‘Test Address ‘+i;

        i++;

        accToUpdate.add(acc);

}

if(!accToUpdate.isEmpty()){

update accToUpdate; 

}

}

2. Trigger Helper Class Pattern:

According to “Best Practices” suggested by Salesforce, we should always use a Helper Class (Apex Class) with a Trigger.

It is a design pattern which makes it easy to maintain the code in the long term.

Common Avoidable Practice:

Salesforce record changes → Trigger containing all the performing code, executes → End

Best Practice:

Salesforce record changes → Trigger calls out to one or multiple classes → Class contains the performing code which executes → End

Example:

Let’s understand the concept of Trigger Helper Class Pattern with an example of a Trigger on Account object, which fires for all the Trigger events.

trigger accUpdate on Account (before insert, after insert, before update, after update)

{

if(Trigger.isBefore)

{

If(Trigger.isInsert) {

// execute first trigger

AccTriggerHelper.firstMethod(Trigger.new);

// execute second trigger

AccTriggerHelper.secondMethod(Trigger.new);

// both of these trigger will follow the execution order

}

Else if(Trigger.isUpdate)

{

// write the code for before update

}

Else if(Trigger.isDelete)

{

// write the code for before delete

}

Else if(Trigger.isUndelete)

{

// write the code for before undelete

}

}

Else if(Trigger.isAfter)

{

If(Trigger.isInsert)

{

// write the code for after insert

}

Else if(Trigger.isUpdate)

{

// write the code for after update

}

Else if(Trigger.isDelete)

{

// write the code for after delete

}

Else if(Trigger.isUndelete)

{

// write the code for after undelete

}

}

}

Handling Recursion in Triggers:

Recursion in Triggers happens when a Trigger is called repeatedly, resulting in an infinite loop.

To counter recursion, we need to:

  1. Create another class called RecursiveTriggerHandler.
  2. Make use of “Static” variables.

Example:

public class RecursiveTriggerHandler { 

public static Boolean isFirstRun = true; 

}

trigger BranchTrigger on Branch__c (before update) {

  if(RecursiveTriggerHandler.isFirstRun){ 

RecursiveTriggerHandler.isFirstRun = false;

// Call Helper Class method

BranchTriggerHelper.firstMethod(Trigger.new);

}

The first instance of the Trigger is run and if this variable is true, the logic in the Helper Class executes.

Other Best Practices for writing triggers:

  1. Always create only one Trigger per object.
  2. Create logic-less Triggers and use Helper Class Design Pattern in which the helper class will contain all the logic.
  3. Create context specific handler methods in the Helper Class.
  4. Bifurcate “insert” and “update” Trigger logic contexts and create two different methods in the Trigger’s helper class.

Example:

trigger PositonTrigger on Position__c (after insert, after update) { 

if(Trigger.isAfter && Trigger.isInsert) { PositionTriggerHandler.handleAfterInsert(Trigger.new); 

} else if(Trigger.isAfter && Trigger.isUpdate) { PositionTriggerHandler.handleAfterUpdate(Trigger.new, Trigger.old); 

}

Our Recent Blog

Share This Post