SFDC

Simplifying field change criteria on Apex Triggers

Posted on October 10th, 2014 at 11:32 am

Defining field criteria for Apex Triggers can be quite cumbersome. For instance, you might have noticed when creating a Salesforce workflows, you can use a function called ISCHANGED(field). Since we don't have any built-in functions for triggers, I decided to create my own.

Take a look at the following example. We want to update a list of accounts, but only when the fields Name, AnnualRevenue, Industry, or Description are updated. Here's how you would do this without my helper methods:

//Create a list for storing accounts with changes
List<Account> accountWithFieldChangesList = new List<Account>();
//Create a set to prevent duplicate accounts from being count
Set<Account> accountWithFieldChangesSet = new Set<Account>();
//Loop through all accounts in the Trigger
for(Account act : Trigger.new){
//Identify the original record
Account oldAct = Trigger.oldmap.get(act.Id);
//If the Name field has changed, add it to the set
if(act.Name != oldAct.Name){
accountWithFieldChangesSet.add(act);
}
//Continue with AnnualRevenue
if(act.AnnualRevenue != oldAct.AnnualRevenue){
accountWithFieldChangesSet.add(act);
}
//Etc.
if(act.Industry != oldAct.Industry){
accountWithFieldChangesSet.add(act);
}
//Etc.
if(act.Description != oldAct.Description){
accountWithFieldChangesSet.add(act);
}
}
//Now check if the set is empty
if(!accountWithFieldChangesSet.isEmpty()){
//Add the set values to the list
accountWithFieldChangesList.addAll(accountWithFieldChangesSet);
//Finally update our list
update accountWithFieldChangesList;
}

Not only does this hard to read, but it doesn't follow the DRY (Do not repeat yourself) principle. And what happens when we add more complexity? This can become a big mess really quickly.

Solution

My solution is to create a helper class I called: HelperTriggerUtility. This class creates an object that require a new and old sObject record in it's constructor and then allows you to check if a single field has changed with the hasFieldChanged(fieldname) method. If you need to check multiple fields, you can use the hasAnyFieldChanged(List<String> fieldnames) method.

Implementation

Let's see how this works:

//Create a list for storing accounts with changes
List<Account> accountWithFieldChangesList = new List<Account>();
//Loop through all accounts in the Trigger
for(Account newAct : trigger.new){
//Identify the original record
Account oldAct = Trigger.oldmap.get(newAct.Id);
//Initialize the helper object and inject the old and new account record
HelperTriggerUtility helper = new HelperTriggerUtility(oldAct, newAct);
//Create a list of fields that we want to check.
List<String> fieldList = new List<String>{'Name','AnnualRevenue','Industry','Description'};
//Run the helper method
Boolean pass = helper.hasAnyFieldChanged(fieldList);
//Add to list if account passes
if(pass){
accountWithFieldChangesList.add(newAct);
}
}
//Check if the list is empty
if(!accountWithFieldChangesSet.isEmpty()){
//Update our list
update accountWithFieldChangesList;
}