+ Start a Discussion
Harjeet Singh 13Harjeet Singh 13 

How to bulkify triggers

Dear All,

I am immense need of help from all of you. After giving a much thought and so much brainstorming happened finally I turned up here for advise.

I need to fetch coordinates value of account based on Map address provided

Solution approach
I create few fields on accounts like MapAddressCity,MapAddressState,MapAddressStreet,MapAddressPostalCode and MapAddresscountry on account. When an user enters values in Map fields and clicks on save button I am calling Google API. Google API will returns one coordinate value based on address filled in Map fields. I have created one field called "Location"(Data Type-Geolocation) which will stores coordinates and also I created 2 formula fields which stores the longitude and latitude values of coordinates in "LonField" and "LatField" respectively

If an user enters below in account:
MapAddressCity: San Francisco  
MapAddressCountry: United States  
MapAddressPostalCode: 94105  
MapPostalState: CA  
MapAddressStreet: One Market Street
and clicks on Save-Google API call will be made and below information wiull be stored on account:
Location-37°47'38''N 122°23'41''W  

My Question:
In our org there is already one trigger written on account and there is already one accounthandler class and we always follow best practices so I didnt write a separate trigger and class to achieve above mentioned requirement. I am reusing same accounttriggerhandler class and apex trigger which is written on account.
If I write separate class and trigger to achieve above mentioned functionality then I have no issue everything works smoothly but when I am trying to include my code in already existing account trigger handler then I am not able to make my code bulkify. I am calling my class method on after insert and after update and coordinates fields are updating perfectly but only for single account because I am not able to make my code bulkify and runs for multiple accounts.

Kindly help me. Below is trigger which is already existing on account:
//Single Master Trigger on Account using Handlers for each individual actions
trigger AccountTrigger on Account (before delete, before insert, before update, after insert, after update,after delete) {

    checkRecursive.isRunOnce = true; // ToDo : Need to change the recursive handling logic
    AccountTriggerHandler accHandler = new AccountTriggerHandler(trigger.new,trigger.old,trigger.newMap,trigger.oldMap,trigger.isUpdate);
    if(trigger.isBefore && trigger.isInsert){
    if(trigger.isBefore && trigger.isUpdate){
    if(trigger.isAfter && trigger.isInsert) {  
    if(trigger.isAfter && trigger.isUpdate){
    if(trigger.isBefore && trigger.isDelete)

    if(trigger.isAfter && trigger.isDelete)

My class code is as belows:
//Handler Class to handle Account Trigger
public class AccountTriggerHandler {
    public static Boolean runAccountTriggerHandler = true;
    private static Boolean geocodingCalled = false;

    public static boolean run = true;
    public static boolean runOnce(){
            return true;
            return run;
    //trigger variables
    List<Account> newAccs;
    List<Account> oldAccs;
    Map<Id,Account> newAccMap;
    Map<Id,Account> oldAccMap;
    Id accountId;
    boolean isUpdate;
    public AccountTriggerHandler(List<Account> newAccs, List<Account> oldAccs, 
                                 Map<Id,Account> newAccMap, Map<Id,Account> oldAccMap, boolean isUpdate){
        this.newAccs = newAccs;
        this.oldAccs = oldAccs;
        this.newAccMap = newAccMap;
        this.oldAccMap = oldAccMap;
        this.isUpdate = isUpdate;
        this.accountId= accountId;                          
        this.consentService = new ConsentManagementService(Account.sObjectType);

    public void HandleAfterInsert(){ 
    public void HandleAfterUpdate(){

    public void HandleBeforeDelete(){
    public void HandleAfterDelete(){
    // wrapper method to prevent calling futuremethods from an existing future context
public static void DoAddressGeocode(id accountId) {
 				 if(geocodingCalled || System.isFuture()) {
                    System.debug(LoggingLevel.WARN,'***Address Geocoding Future Method Already Called - Aborting...');
  		// if not being called from future context, geocode the address
  						geocodingCalled= true;
    @future (callout=true)  // future method needed to run callouts from Triggers
      static public void getLocation( id accountId){
        // gather account info
      Account a =[SELECT MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account  WHERE id =: accountId];
      //List<Account> a= new List<Account>();
      //a= [SELECT id, MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account  WHERE id =: accountId];
        // create an address string
        String address = '';
        if (a.MapAddressStreet__c!= null)
            address += a.MapAddressStreet__c+', ';
        if (a.MapAddressCity__c != null)
            address += a.MapAddressCity__c +', ';
        if (a.MapPostalState__c!= null)
            address += a.MapPostalState__c+' ';
        if (a.MapAddressPostalCode__c!= null)
            address += a.MapAddressPostalCode__c+', ';
        if (a.MapAddressCountry__c!= null)
            address += a.MapAddressCountry__c;

        address = EncodingUtil.urlEncode(address, 'UTF-8');

        // build callout
        Http h = new Http();
        HttpRequest req = new HttpRequest();

            // callout
            HttpResponse res = h.send(req);

            // parse coordinates from response
            JSONParser parser = JSON.createParser(res.getBody());
            double lat = null;
            double lon = null;
            while (parser.nextToken() != null) {
                if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) &&
                    (parser.getText() == 'location')){
                       parser.nextToken(); // object start
                       while (parser.nextToken() != JSONToken.END_OBJECT){
                           String txt = parser.getText();
                           if (txt == 'lat')
                               lat = parser.getDoubleValue();
                           else if (txt == 'lng')
                               lon = parser.getDoubleValue();


            // update coordinates if we get back
            if (lat != null){
                a.Location__Latitude__s = lat;
                a.Location__Longitude__s = lon;
                update a;

        } catch (Exception e) {


I have removed all the extra codes and methods from class and only kept my method in class to have a better visibility for code to all of you.
I am calling "DoAddressGeocode​" method on HandleAfterInsert and HandleAfterUpdate.
Right now I am not able to do bulkification of my code and wrote only for 1 accounts like DoAddressGeocode(newAccs[0].id)

Any help would be greatly appreciated.

Thanks in advance!

Kindly help

Tuan LuTuan Lu
You might want to for loop through newAccs instead of just processing the [0] index account. Also having hard rule of 1 trigger for an object is also not good neither from a general software dev best practice or a admin operations best practice. I might write a blog about this. Also there is a transaction CPU timeout in Salesforce of 10 seconds. You should consider using a asynch or batch process to update the account geo fields otherwise your callout will consume most of your CPU time. I provide consulting services is you want to talk about your design. LMK thanks. 
Harjeet Singh 13Harjeet Singh 13
Dear Tuan,

Thanks for your kind response.

I will be happy to get in touch with you If I will be able to solve my bulkification issue.

Many thanks in advance

Thanks & Regards,
Harjeet Singh 13Harjeet Singh 13
Dear Tuan,

I am using future callout for updating geofields.Kindly refer 85 of my class

Thanks & Regards,