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 trigger.new 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 trigger.new and trigger.old data into Lists declared in my APEX Class
clsHistoryChecker.lstNewEvents = Trigger.new;
clsHistoryChecker.lstOldEvents = Trigger.old;

// Trigger Logic – Before Update
if(trigger.isBefore && trigger.isUpdate) {
clsHistoryChecker.checkPreviousValues();
}

}

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!

Advertisements

11 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?

    Thanks,
    Ankur

    • 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.

      -Andy

  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: Trigger.new) {
    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 = System.now() + .33334;
    }
    }
    }

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

    Thanks,
    Bob

    • 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?

      -Andy

  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 = System.now() + .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,

    Bob

    • 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,
    Ferdinand

  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.)

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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 )

Google+ photo

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

Connecting to %s