function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
mgodseymgodsey 

Trigger updating a field twice?

I have a trigger written that updates a field on an Opportunity based on whether or not another field is null. The trigger is firing, but it seems to be firing twice? 

 

For example, what I would expect to see is if the Opportunity meets the criteria (VersionType__c == 'Change Request' && ApprovalStatus__c == 'Approved' && ChangeTag__c == 'null') and AdServer__c != null and Retargeting__c!=null, then the ChangeTag__c field would update to say 'Ad Server Change; Retargeting Change'. However, it updates to 'Ad Server Change; Ad Server Change; ReTargetingChange; ReTargetingChange". 

 

I cannot figure out why this would be happening. The System debug for the ID List returns only 1 ID (like it should). Any ideas what is happening here? Thank you!

 

Here is the code:

trigger ChangeTagOpp on Opportunity (after update) {

//(1) define variable for list of all ChangeRequestIDs (2) that are approved

List<ID> ChangeRequestIDs = new List<ID>();
    for(Opportunity crOpp: trigger.new){
    if(crOpp.versiontype__c =='Change Request' && crOpp.ApprovalStatus__c =='Approved'&& crOpp.ChangeTag__c==null){
        ChangeRequestIDs.add(crOpp.id);
        }
        System.debug('*************Opps in ID List**********' + ChangeRequestIDs);
}
//(3) get ids and field for change request forms
List<Opportunity> changerequests = new List <Opportunity> ();
for (Opportunity crOpp:[SELECT ID, AdServer__c,ReTargeting__c, ChangeTag__c 
                      FROM Opportunity
                      Where ID in: ChangeRequestIDs]) {                 

//(4) select Change Tag reaons based on fields completed on change request form
    if(crOpp.AdServer__c !=null){crOpp.ChangeTag__c +=';Ad Server Change';}
    if(crOpp.Retargeting__c!=null){crOpp.ChangeTag__c+=';ReTargetingChange';}
    crOpp.ChangeTag__c = crOpp.ChangeTag__c.replaceAll(';?null;?',' ');
    
    changerequests.add(crOpp);

//(5) update Change Tag field on approved change request forms
}
update changerequests;
}

 

Best Answer chosen by Admin (Salesforce Developers) 
BritishBoyinDCBritishBoyinDC

Ideally, you'd move all the logic from those six triggers into one ore more handling classes, and just have one trigger firing - that way you can control the timing and execution in a way you can't right now.

 

I've always found this article a good starting point:

http://gokubi.com/archives/two-interesting-ways-to-architect-apex-triggers

 

This is the approach I use - one trigger per object, that then calls static methods for each trigger operation (e.g. before insert, before update) in one main handling class, which in turn uses additional methods/classes to execute particular logic. But as you'll see if you do a search for apex design patterns, there are various articles on this subject, and various approaches that have different pros and cons.

 

But one of the approaches suggested in the above article would go a long way to helping you to control the execution flow...

 

If you prefer to stay with the code as is, it just depends on whether the other triggers are affected by the code double firing - if not, you can probably leave it for now, but at some point, but you'll likely need to control the logic in each trigger...

All Answers

BritishBoyinDCBritishBoyinDC

Because this is written as an after update, you are triggering a second update to the record, which is firing the trigger again, but the values being processed in the trigger are based on the original values at the start of the context...

 

You can either prevent the trigger firign again - see here for an explanation:

http://www.salesforce.com/docs/developer/cookbook/Content/apex_controlling_recursive_triggers.htm

 

Or you can probably move this to before update, which should prevent the second update being triggered

mgodseymgodsey

I thought that might be it, but if it was continuing to update wouldn't it enter a continous loop and fail? I'm not sure why it would stop after just two. I believe that because the ChangeTag__c field is no longer null after the first update, the trigger should stop firing. Am I thinking about this incorrectly, though?

BritishBoyinDCBritishBoyinDC

Salesforce has built in constraints to avoid infinite recursion, so it will only fire twice...

 

I would move the logic to the before update context and see if that fixes it... 

sfdcfoxsfdcfox

The problem is actually different than what the other posters here have mentioned. You have a Workflow Field Update that's modifying the record you're processing, which causes your Before and After triggers to fire a second time. Were it an infinite recursion problem, it wouldn't fire twice, but instead fire 16 times and bail out. Set a static variable that will be checked before execution, and if true, break early, otherwise perform normal processing, then set the static variable to true.

 

trigger X on Y ( ... ) {
  if( flags.recursivetrigger ) {
    return;
  }
  flags.recursivetrigger = true;
  // more processing
}

 

public class flags {
  public static boolean recursivetrigger;
  static {
    recursivetrigger = false;
  }
}

 

BritishBoyinDCBritishBoyinDC

Ah, I stand corrected...sfdcfox sounds right on this one. I do believe workflow has constraints to stop it creating infinite update loops, but having encountered the recursive loop error in triggers, your comment about it firing twice should have been my clue...

 

One thought on sfdcfox's solution - if workflow is firing, and causing updates your trigger cares about,  check that you don't actually want the logic to fire twice but with different operations - that has caught me out on occasion..

mgodseymgodsey

Thanks so much for the help, guys. I tried verifying that it was an issue with workflow rules, but after deactiving atll workflow rules for the Opportunity object (where this trigger is firing from), I still get the doubled response. Also to note, I have the same exact trigger except on a different object (which does have workflow field updates), and I'm not running into any trouble there.

 

I think the issue is that I have 6 triggers firing from the Opportunity, so any change causes a chain reaction. I'm going to try setting the static variable on the Change Tag trigger, but do you think I"ll need to do it on all the triggers?

BritishBoyinDCBritishBoyinDC

Ideally, you'd move all the logic from those six triggers into one ore more handling classes, and just have one trigger firing - that way you can control the timing and execution in a way you can't right now.

 

I've always found this article a good starting point:

http://gokubi.com/archives/two-interesting-ways-to-architect-apex-triggers

 

This is the approach I use - one trigger per object, that then calls static methods for each trigger operation (e.g. before insert, before update) in one main handling class, which in turn uses additional methods/classes to execute particular logic. But as you'll see if you do a search for apex design patterns, there are various articles on this subject, and various approaches that have different pros and cons.

 

But one of the approaches suggested in the above article would go a long way to helping you to control the execution flow...

 

If you prefer to stay with the code as is, it just depends on whether the other triggers are affected by the code double firing - if not, you can probably leave it for now, but at some point, but you'll likely need to control the logic in each trigger...

This was selected as the best answer