Apex Triggers in Salesforce




Apex Triggers are event handlers. Whenever a record is inserted, updated, deleted, or undeleted the Salesforce.com system will “fire” or execute the trigger event.

Salesforce will actually execute a trigger in two different contexts: before and after.

Before-trigger events are executed before a record has been committed to the database.

While after-trigger events are executed after a record is committed to the database.

When to use Before Trigger

Before-trigger events occur before a record’s changes are committed to the database.

This particular event is ideal for performing data validation, setting default values, or performing additional logic and/or calculations.

Please keep in mind that in the case of before-insert events, because the event is executed before the record is committed to the database it will not have a record id.

Before-triggers in my opinion are the most efficient and are going to be your goto method for most of the triggers you will write for a couple of reasons.

The first being that you can perform data validation and reject a record before it is committed to the database, meaning there is no cost to performance by the system having to roll back an update.

Second, you can update fields or set default values for a record without having to initiate another DML command.

For example the code below illustrates setting a default value on a record. No DML required.

trigger setDefaultAccountValues on Account (before insert, before update) {
   for (Account oAccount : trigger.new) {
  oAccount.Industry = ‘Cloud Computing’;
   }
 }


…and that is it. As you can see I simply just set the value of the field I want to change or default. Salesforce will take care of the rest.

When to use After Trigger

After-trigger events occur after a record has been committed to the database, which means that records being inserted will have a record id available.

This particular event is ideal for working with data that is external to the record itself such as referenced objects or creating records based on information from the triggered object.

Another key best practice for after-trigger events is that while it is possible to perform a DML operation on the record that initiated the trigger event, it should be avoided.

If we think it through, when you perform a DML operation on a record from a trigger event the system will need to execute all triggers on that object again, not only does this impact performance but it puts us at risk of creating an infinite loop


For example the code below illustrates creating an Opportunity after an Account is created

trigger createNewAccountOpportunity on Account (after insert) {
    List<Opportunity> listOpportunities = new List<Opportunity>();

    for (Account oAccount : trigger.new) {
        Opportunity oOpportunity = new Opportunity();
        oOpportunity.Name = oAccount.Name;
        oOpportunity.AccountId = oAccount.Id;
        oOpportunity.Stage = Proposal;
        oOpportunity.CloseDate = System.today() + 30; //Closes 30 days from today

        listOpportunities.add(oOpportunity);
    }

    if (listOpportunities.isEmpty() == false) {
        insert listOpportunities ;
    }
}


Example 2 :

trigger exampleInvalidTrigger on Opportunity (before insert, before update) {
    for (Opportunity oOpportunity : trigger.new) {
        if (oOpportunity.Owner.Profile.Name == Executive) {
            oOpportunity.IsExecutiveOpportunity = true;
        }
    }
}


Example 3 :


trigger exampleValidTrigger on Opportunity (before insert, before update) {
    Map<Id, User> mapUsers = new Map<Id, User>([SELECT Id, Profile.Name       FROM User]);

    for (Opportunity oOpportunity : trigger.new) {
        User oOwner = mapUsers.get(oOpportunity.OwnerId);

        if (oOwner.Profile.Name == Executive) {
            oOpportunity.IsExecutiveOpportunity = true;
        }
    }
}


Writing Bulk Trigger


All triggers execute in batch mode, meaning whether it is single record or a hundred you will always need to use the trigger.new collection .

We should prepare your trigger to be able to handle a batch of records.

We have to take care on how we query additional information and also keep in mind how many script statements we are executing per record.

"Bad Example"
trigger badExample on Opportunity (before insert, before update) {
    for (Opportunity oOpportunity : trigger.new) {
  User oOwner = [SELECT Id, Profile.Name FROM User WHERE Id =
   :oOpportunity.Id];

         if (oOwner.Profile.Name == ‘Executive’) {
            oOpportunity.IsExecutiveOpportunity = true;
        }
    }
}

"Good Example but not worthy enough"

trigger exampleGoodButInefficientTrigger on Opportunity (before insert, after update) {
    Map<Id, User> mapUsers = new Map<Id, User>([SELECT Id, Profile.Name FROM User]);

    for (Opportunity oOpportunity : trigger.new) {
        User oOwner = mapUsers.get(oOpportunity.OwnerId);

        if (oOwner.Profile.Name == ‘Executive’) {
            oOpportunity.IsExecutiveOpportunity = true;
        }
    }
}


"Better Example"


trigger exampleBetterTrigger on Opportunity (before insert, after update) {
    Set<Id> ownerIds = new Set<Id>();

    for (Opportunity oOpportunity : trigger.new) {
        ownerIds.add(oOpportunity.OwnerId);
    }

    Map<Id, User> mapUsers = new Map<Id, User>([SELECT Id, Profile.Name FROM User WHERE Id IN :ownerIds]);

    for (Opportunity oOpportunity : trigger.new) {
        User oOwner = mapUsers.get(oOpportunity.OwnerId);

        if (oOwner.Profile.Name == Executive) {
            oOpportunity.IsExecutiveOpportunity = true;
        }
    }

}


"Best Example"

trigger exampleBestTrigger on Opportunity (before insert, after update) {
    Set<Id> oppIds = trigger.newMap.keySet();

    Map<Id, User> mapUsers = new Map<Id, User>([SELECT Id, Profile.Name
   FROM User WHERE Id IN (SELECT OwnerId FROM Opportunity
   WHERE Id IN :oppIds)]);
    for (Opportunity oOpportunity : trigger.new) {
        User oOwner = mapUsers.get(oOpportunity.OwnerId);

        if (oOwner.Profile.Name == Executive) {
            oOpportunity.IsExecutiveOpportunity = true;
        }
    }
}


//Single Trigger for Before and After Events
trigger AccountEventListener on Account (before insert, after insert, before update, after update) {
    if (trigger.isBefore) {
        if (trigger.isInsert || trigger.isUpdate) {
            //DO SOMETHING
        }
    }
    else if (trigger.isAfter) {
        if (trigger.isInsert || trigger.isUpdate) {
            //DO SOMETHING
        }
    }
}

//Before Event Trigger
trigger AccountBeforeEventListener on Account (before insert, before update) {
    if (trigger.isInsert || trigger.isUpdate) {
        //DO SOMETHING
    }
}

//After Event Trigger
trigger AccountAfterEventListener on Account (after insert, after update) {
    if (trigger.isInsert || trigger.isUpdate) {
        //DO SOMETHING
    }

} 



Apex Triggers in Salesforce Apex Triggers in Salesforce Reviewed by dasfrogpractice on 12:03 Rating: 5

1 comment:

  1. Neat explanation and comparative approaches of bad, good, better, best

    ReplyDelete

Theme images by mariusFM77. Powered by Blogger.
Youtube Channel Image
Dasfrog Subscribe To watch more Salesforce Training
Subscribe