Comparing new values vs. old values in APEX Trigger

I came across a situation today where I needed to compare new vs. old values in an APEX Trigger to determine a course of action.  Here is a slick little way to do this without having to worry about if Salesforce decided to correctly order your trigger.old in the same way that is.

Here is the APEX Trigger:

trigger historyCheckerLogic on Event (before update)

// This trigger handles record updates from the EVENT object
// Reference:  (class) historyChecker.checkPreviousValues()
// (other nice little header info)

// Declare APEX Class where work will be done (I try not to ever do any work inside of a trigger)
public historyChecker clsHistoryChecker = new historyChecker();

// Put and trigger.old data into Lists declared in my APEX Class
clsHistoryChecker.lstNewEvents =;
clsHistoryChecker.lstOldEvents = Trigger.old;

// Trigger Logic – Before Update
if(trigger.isBefore && trigger.isUpdate) {


Here is the APEX Class:

public class historyChecker {

// This class handles logic from the historyCheckerLogic trigger
// (other nice little header info)

public List<Event> lstNewEvents = new List<Event>();
public List<Event> lstOldEvents = new List<Event>();

public void checkPreviousValues() {

// This method compares old values to new values from the historyCheckerLogic trigger

// Declare method variables
Map<Id, Event> mapVerifyOldEvents = new Map<Id, Event>();

// Create initial Map of old Events
for(Event evtOld : lstOldEvents) { mapVerifyOldEvents.put(evtOld.Id, evtOld); }

// Loop through lstNewEvents and check old values
for(Event evtNew : lstNewEvents) {

if(evtNew.ActivityDate != mapVerifyOldEvents.get(evtNew.Id).ActivityDate) {

// The values are NOT the same, do whatever logic you want…
evtNew.addError(‘Ummm, you can’t change this field!’);





I remember looking high and low for a way to efficiently do this a while back – so hopefully if you’ve found my page I’ve helped you out a little with your question.  Please feel free to ask me other related questions in the comments below.

Thanks for readying and happy coding!


13 thoughts on “Comparing new values vs. old values in APEX Trigger

  1. Hi Techman97,

    I know when you delete a parent object the child objects are also deleted.
    But does deleteting a parent record fire (before / after) delete triggers on child objects? I would think this to be the case, but am seeing otherwise in Delete of Quote. There does not seem to be anything delete triggers being invoked on QLI.

    Do you know what this happens?


    • Hello Ankur!

      On delete of the parent, the delete triggers for children do not fire. There are a few Ideas out on the IdeaExchange that speak to this. What I would recommend is to query for and do actual deletes of the child records from the parent delete trigger to be 100% sure that your triggers are being fired.

      You’ll also want to make sure that you’re firing the child delete logic on a BEFORE DELETE trigger or you’ll find that your child records have already been deleted by the time the AFTER DELETE fires.


  2. Andy –
    I’m tracking durations between workflow steps using standard field tracking history each time an assignee field changes, so trying to use the ‘before update’ trigger to write a specific (same) date/time to the ‘end’ date for the old history record and to the ‘start’ date/time for the ‘new’ history record.

    I was successful in writing the date to the ‘old’ record, but have not been able to get the ‘new’ transaction to work.

    Here’s what I think worked for the old, to write the end date/time to the old record…

    trigger tgrPopulateQuoteRequestStatusDuration on Quote_Requests__c (before update){
    for (Quote_Requests__c q: {
    Quote_Requests__c oldActivityAssignee = Trigger.oldMap.get(q.ID);
    if(q.Current_Action_Assignee__c != oldActivityAssignee.Current_Action_Assignee__c) {
    q.Assignee_Action_End__c = + .33334;

    I’m also trying to write the start date/time to the new record:
    q.Assignee_Action_Start__c = + .33334;


    • Bob,

      All in all it looks like your code is sound, although I’m curious about the +.33334 part.

      Using the “before update” is the correct scope to update a field on the triggered record(s) before committing to the database – I guess all I could suggest at the moment is to put some System.Debug statements in there and see where your logic is breaking down?


  3. Thanks Andy,

    The top part does work for writing to the ‘old’ version of the record. I’m having trouble proving that the additional line (q.Assignee_Action_Start__c = + .33334;) writes to the ‘new’ version since SF Reports is not showing me access to the history table of this Master-Detail child object. I’ll test it again in production.

    The +.33334 is a time zone adjustment for GMT-8, so that I’m calculating all of our entries from various locations based on our California time zone.

    I appreciate any other suggestions.

    Best regards,


    • Your “q” variable in the loop is indeed pointing at the record being updated – and your “before” scope allows that field to be modified before commit.

      Is it not updating?

  4. Thanks Andy!

    This has been very helpful for me!

    I have a question concerning this trigger & class. I am trying to write a testclass for this, but I keep getting different errors.

    Could you possibly show how you wrote your testclass for this example?

    Kind regards,

  5. hi techman ,i’m new to salesforce development can you tell me why we should have separate class for implementing trigger functionality rather than writing in the same trigger. To be straight what is the advantage of not coding much functionality in trigger??

    • Manoj,

      A good best practice is to get any kind of business logic out of your triggers so you are able to reuse it through other means (other triggers, classes, etc.)

  6. got a requirement like to calculate average in account based on particular record type of case. My requirement is:

    I have a field called ARP in account currency. I want to calculate overall average of ARP field in particular record type called customer order whether Case details either new or add-on.

    So I’m trying write a trigger a trigger.

    Everything is working but after delete event is not working means.

    Example when i create a case with ARPU will be 21.And if i delete the case it’s still showing 21 in account level.Even i am passing trigger.old in trigger to handler class for deletion method.

    public static void ARPUDelete(List CaseTriggers)
    * This method is to caluclate average of all ARPU amounts with case have customer order recordtype
    * as well as case details with either ADD-On (OR) New Subscription and update in related account
    * field called ARPU.
    * This method will fire only when any case with record type called customer order is deleted.
    Id recordTypeId = [Select Id From RecordType Where DeveloperName = ‘Customer_Order’].Id;
    List CaseIDs = new List();
    if (Trigger.IsDelete)
    for (Case s : CaseTriggers)
    if(s.RecordTypeId == recordTypeId && s.Case_Details__c ==’New Subscription’ || s.Case_Details__c ==’Add On’ )
    // Loop through and add caseId’s to the list.
    system.debug(‘Case:IDS ‘ + caseIds);
    /** @Var CaseAccountIds – to get accountId’s of cases with list called CaseIDs */
    set CaseAccountIds = new set();
    List Accountstoupdate =new List();
    for(Case c : [SELECT Id,ARPU__c,accountId FROM Case WHERE Id IN :CaseIDs])
    // Loop through and add AccountId’s to the list.
    system.debug(‘CaseAccount IDS ‘ + CaseAccountIds);
    /** @Var Accountswithcases-to get account details to caluclate average */
    /** @Var results-to get average of particular account based on the cases */
    List Accountswithcases = [select Id,name,ARPU__c from Account where id =:CaseAccountIds];
    system.debug(‘Accounts With Cases ‘ + accountsWithCases);
    system.debug(‘Accounts With Cases Size’ + accountsWithCases.size());
    Map results = new Map(
    [SELECT AccountId Id, AVG(ARPU__c) average FROM Case WHERE AccountId = :Accountswithcases GROUP BY AccountId]);
    system.debug(‘Results ‘ + results);
    system.debug(‘Results Size ‘ + results.size());
    For(account a1: Accountswithcases)
    if(results.get(a1.Id) != null)
    // Loop through aggregate results array and typecast the average of ARPU and update in account level.
    system.debug(‘Updating Account ARPU ‘ + a1.ARPU__c);
    a1.ARPU__c = (Decimal)results.get(a1.Id).get(‘average’);
    system.debug(‘Updated Account ARPU ‘ + a1.ARPU__c);

    // DML statement to update all the accounts related with cases.
    system.debug(‘Updating Records ‘ + AccountsToUpdate);

    update Accountstoupdate;

    Please help me where i went wrong in my code

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s