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
SFDummySFDummy 

Trigger being called twice

Hello,

 

I have a trigger on Account and it is being called twice I am do not know how to figure this out.

 

Here is my trigger code

 

 

trigger AccUpdateRates on Account (before insert, before update) {
  for(Account a: Trigger. new){
    if(Trigger.isUpdate){
      Account beforeUpdate = System.Trigger.oldMap.get(a.Id);
       if(a.RecordTypeId == '012500000001LcY' && a.Termination_Date__c == null){
        }
     }
     if(Trigger.isInsert){
        if(a.RecordTypeId == '012500000001LcY' && a.product__c != null){
              AccList.add(a);
              prodIDs.add(a.product__c);
          }    
     }
    if(accList.size()>0)
      AccountUpdateRates.UpdateProductRates(AccList, ProdIDs);

   
   }


}

I see that I have Kugadd package installed and have similar trigger on account. 

   Trigger - AccountBeforeInsertBeforeUpdate - installed package Kugamon Account/Contact Sync

 

 

I put print statement in couple of place in my class that is being called from trigger. 

 

When I look at the debug log I see the following statement twice

16:05:48.163|CODE_UNIT_STARTED|[EXTERNAL]|01qP00000004GdG|AccUpdateRates on Account trigger event BeforeUpdate for [0015000000XLDub]

Any suggestions I can find what is my causing trigger to be called twice?

 

Thanks

Uma

homersantoshomersantos

http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_triggers_order_of_execution.htm

 

According to this your trigger is hitting a workflow that changes the record again and then it redoes the trigger. 

SFDummySFDummy

Thanks for the information. how can I prevent from trigger being called twice?

 

what should I look for in debug log?

Is there any check I can do to make sure that the trigger does not fire second time?

b-Forceb-Force

There is no any straight way to prevent execution of trigger,

here is workaround.

 

Create a Boolean Field on your Object, like flag__c

Now update this flag while updating records ..via apex or Workflow rule field upadate

Use this same field as controlling field in Apex code

In this way , You can avoid execution of Core logic of Trigger

 

Hope This will help you,

 

Thanks,

Bala

 

 

 

Ritesh AswaneyRitesh Aswaney

Just to add to Bala's response, this boolean flag should be static, so that it is available throughout the execution context.

 

http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_static.htm

SteveBowerSteveBower

I don't think you should focus on finding a way to stop your trigger from being called multiple times in one execution 'stream'.   Rather, I think you'd be better served by making sure that your trigger only does necessary work each time it's called.   Right now perhaps you only have that one package you've mentioned, but later you may have more, and other packages can also install workflows and triggers that in turn may call yours again and again, etc.   

 

For example, the first time your trigger executes I assume you plan to call UpdateProductRates.   But, the second time through your trigger I'd guess that there would be something set by the UpdateProductRates call that you could check to see if an update is required.  If it is, do it, otherwise don't.

 

 

Some other thoughts:

 

1. Don't hardcode your RecordtypeId's.     use:

if (a.RecordTypeId == [select id from RecordTypes where sobjecttype= 'Account' and Name='theRecordTypeName'].id;

 

If you use that ID several times, create a local ID variable and retrieve it once.

 

 

2. Push logic into your utility libraries.  For example, in this usage, the UpdateProductRates utility is taking parallel lists of Account SObjects and Product ID's.   However, all the Product ID information is already in the Account information.  So, why not write an UpdateProductRates(List<Account> accs) version that accepts the list and (if needed) extracts the product ID's into it's own list.   Take that logic out of the trigger.

 

Also, going back to the first paragraph, call UpdateProductRates multiple times... let *that* library figure out if there's work to do on it's targets.   (And it should check for isEmpty() on it's arguments as well and return right away if the argument list(s) is empty.)

 

Hope this helps, Best, Steve.

 

 

SFDummySFDummy

Thanks for all the suggestions.

 

I took all the points mentioned by SteveBower into consideration and made changes to my trigger and class.

 

I am creating a task in my package that acts as a Activity History.  This task is being created twiceInsert Task in apex Class because the tirgger is being called twice. I am trying to prevent that.

Secondly, I am setting a flag  Updated ="True"  to prevent users from making changes again within one hour

 

I tried last modified Date compare with date.Today() that did not work. Because Last Modified date is localized where are date.Today() is server time 

 

last modifiedDate: 2011-03-30 19:00:14 now: 2011-03-30 00:00:00
last modifiedDate: 2011-03-30 19:06:37 now: 2011-03-30 00:00:00
I am using static variable as suggested to prevent trigger being fired twice.
Now the question:
I have workflow rules timebased that does field updates. Reset flag Updated__c ="False"
Field updated based on new values - with some calculation.
Is using the static varible to prevent trigger being fired twice is a correct solution? or am I going to have other unforseen issues?
Thanks again and appreciate all your comments/feedback
Thanks

 

 

SteveBowerSteveBower

Instead of Date.today(), could you compare it with DateTime.now()?    LastModifiedDate is stored as Coordinated Universal Time.

 

It's converted by the UI to your timezone, however programatically LastModifiedDate should be directly comparable to DateTime.now().    You should be able to do the comparison in the Query so you don't even have to retrieve the values and check them, you should just be able to do a count() and see if you get any records back.

 

Best, Steve.

 

p.s. I won't ask why you're not using the build-in Activity History capabilities, but be sure to consider it.

GuyClairboisGuyClairbois

Hi,

As a response to your question on using static variables: I try to keep away from it, as it will not always work correctly when working with sets of records larger than 100. In that case, the data is processed in subsets of 200 (each in a separate context) and then within the trigger the subset of 200 is processed in 2 separate sets of 100.

 

The Static Boolean will be set after the first 100 records have been processed, causing the trigger NOT to run for the second set of 100.

 

We had many problems in our org because of this strange APEX behaviour.... I'm puzzled by why this subdivision is made and why it was not simply made 1 dataset in 1 context...

 

Hope that helps,

Guy

Cathy_022Cathy_022

Hi Guy,

 

Were you able to resolve this issue with static variable that prevents the trigger to be executed?

 

Thanks,

Cathy

SFDummySFDummy

Yes, I am able prevent calling trigger twice by using static variable

 

In the controller

AccUpdatesControl.calledOnce = true;

 and here is the static variable value reset

public with sharing class AccUpdatesControl {
   // This class is used to set flag to prevent multiple calls
    public static boolean calledOnce = false;
    
    public static boolean ProdUpdateTrigger = false;

}

 

 

GuyClairboisGuyClairbois

1 small remark on my point above: it seems that this only happens when working with the WebService API and not when e.g. updating 200 records via the List View inline edit function.

 

It appears to me that the only 100% secure option is to work with a checkbox field on the record, that indicates whether or not the trigger as run. Then an @future that resets the checkbox back to unchecked.

 

This was also recommended to me by salesforce developer support.

 

Rgrds,

Guy

Cathy_022Cathy_022

Hi Guy, 

 

Thanks for sharing. I'm actually encountering this issue in Batch APEX. May I know how you implemented the @future?

 

Thanks,

Cathy

Jack D PondJack D Pond
I ran across this when using the trigger to create an event.  When others added workflows and triggers that also did updates, I found the trigger was executed multiple times, causing redundant activities.  To avoid this, I created an APEX " public with sharing" class that had static property(s).  One of those properties was a set which each time the trigger was initially updated, the ID of the tiggering object would be placed in the set as a "Lock", removing it from the set after the record was updated.

Here's the class with the static share property:
// @file
// @author Jack D. Pond <jack.pond@dc.gov>
// @ingroup Queue Management
// @licence GNU General Public License 2.0 or later
// @Description Static Class to keep triggers from executing multiple times, creating
//              redundant entries.
//              
//              By adding a shared class, variables can be shared across processes.  This could also be used
//              to disable triggers for batch processing and testing
//              
//              The concept is to put the id of the triggered object into a set when it is first executed,
//              let that act as a "lock", then removing it after all record updates have been completed
//              
//              The trigger should have both before update, after update activated.  If updates exist in workflows, field updates,
//              or other triggers, any change made in there will reinitiate a new trigger.  This creates a "lock" by adding
//              the object Id into the "updatecalled" set of IDs.  The lock is added the first time a change occurs and triggers
//              the class (Trigger.isUpdate), then checked every time it is run to see if the lock already exists(Trigger.isUpdate),
//              then finally removes the lock after all updates have been processed and the record written (trigger.isAfter)
// 
public with sharing class TeamTrackingLogUpdates {
 public static set<ID> updatecalled = new set<id>();
}

Then added to the trigger:
trigger TechResolutionWorkflow on Case (before update, after update) {
    for ( Case c : Trigger.New ) {
        if (Trigger.isAfter) {
            if (!TeamTrackingLogUpdates.updatecalled.Contains(c.Id)) TeamTrackingLogUpdates.updatecalled.remove(c.Id); // Removes lock once updated
        } else if (!TeamTrackingLogUpdates.updatecalled.Contains(c.Id)) { // Checks Lock, executing code only if no lock
            TeamTrackingLogUpdates.updatecalled.Add(c.Id); // Adds Lock
            //
            // Your code here
            //
        }
    }
}






Eric KintzerEric Kintzer
The static variable approach will not work with AllOrNone = false use cases and where the batch has 1+ successes and 1+ failures. This is because when SFDC retries the successes after putting aside the failures (see doc), the database is rolled back but the static variable is not reset and when the trigger is re-executed in the retry, the static variable will indicate work is already done and the trigger will do nothing. Your database will be left inconsistent.