How can we avoid trigger get executed again and again (recursive trigger)? One way is to have a class with static variable and have boolean value and check it is true or false and changing the boolean according to executing the trigger value. Is there any other way other than this to handle recursive trigger in salesforce. Please guide me the best way to do ?
[SalesForce] How to avoid recursive trigger other than the classic ‘class w/ static variable’ pattern
Related Solutions
Good question, but there are MANY possible answers, so I will just throw in my 2 cents.
The first and easiest way to 'BULKIFY' is to leverage collections in order to save yourself SOQL calls and DML statements.
Here's an older, but still great resource by Jeff Douglass on utilizing collections in Salesforce.
http://blog.jeffdouglas.com/2011/01/06/fun-with-salesforce-collections/
IMO, I would say that leveraging collections is the first and best place to start in trying to optimize and bulkify your triggers. I will now try to show a few examples of how leveraging collections can save you many Governor limit headaches.
This code uses one DML statement for each Account in trigger.new
Trigger myTrigger on Account(after insert) {
for(Account a : trigger.new){
My_Custom_Object__c obj = new My_Custom_Object__c(Account__c = a.Id);
insert obj;
}
}
The example above makes a DML call for every account in trigger.new. If this is a mass insert, you will run into governor limit issues.
This code now uses one DML statement total, regardless of the size of trigger.new
Trigger myTrigger on Account(after insert) {
list<My_Custom_Object__c> objList = new list<My_Custom_Object__c>();
for(Account a : trigger.new){
objList.add(new My_Custom_Object__c(Account__c = a.Id));
}
insert objList;
}
This example moves the DML outside of the loop. Instead you add a new custom object to the list inside of the loop. Once you have gone through the entire list of trigger.new, you insert the list of custom objects.
This code uses one SOQL query for each Account in trigger.new
Trigger myTrigger on Contact(before insert) {
for(Contact c : trigger.new){
if(c.AccountId != null) {
Account a = [Select Id, Name, ShippingCity From Account Where Id =: c.AccountId];
c.ShippingCity = a.ShippingCity;
}
}
}
The example above makes a SOQL query for every contact in trigger.new. If this is a mass insert, you will run into governor limit issues.
This code now uses one SOQL query total, regardless of the size of trigger.new
Trigger myTrigger on Contact(before insert) {
map<Id,Account> accountMap = new map<Id,Account>();
for(Contact c : trigger.new){
accountMap.put(c.AccountId, null);
}
accountMap.remove(null);
accountMap.putAll([Select Id, Name, ShippingCity From Account Where Id In : accountMap.keyset()]);
for(Contact c : trigger.new){
if(accountMap.containsKey(c.AccountId)){
c.ShippingCity = accountMap.get(c.AccountId).ShippingCity;
}
}
}
This example above utilizes a map to store all accounts related to the contacts in trigger.new. The advantage here is that one single SOQL query gathers all the accounts. You can then get the account easily within the loop without have to query the database. You now have the same trigger with a sinlge SOQL query regardless of the size of trigger.new
I believe this is one of the best practices to optimize your triggers for bulk operations.
To take it a step further, there are a few more things that we can do to optimize our triggers. One of the best practices is to only use one trigger per object.
Lets assume you have two specific pieces of business logic that you need to apply after an account is created. The easy way to accomplish this would be to create 2 triggers on the account object.
Trigger myTrigger1 on Contact(after insert) {
//YOUR LOGIC FOR TRIGGER 1
}
Trigger myTrigger2 on Contact(after insert) {
//YOUR LOGIC FOR TRIGGER 2
}
This could work well depending on your situation. What if you have logic in trigger2 that is dependent on the outcomes of trigger1? There is no guarantee the order in which your triggers will run, so in some cases trigger1 will run first and in others trigger2 will run first.
A simple approach to solve this is to combine the logic into a single trigger
Trigger myTrigger1 on Contact(after insert) {
//YOUR FIRST PIECE OF LOGIC
//YOUR SECOND PIECE OF LOGIC
}
This works technically, as you can now control the order of the operations, and it is a best practice to have only 1 trigger per object, but still can be improved a bit. Lets say for arguments sake this is a fairly large trigger, with a few different pieces of complex logic.
Trigger myTrigger1 on Contact(after insert) {
//YOUR FIRST PIECE OF LOGIC
//LOTS OF CODE
//YOUR SECOND PIECE OF LOGIC
//LOTS OF CODE
//YOUR THIRD PIECE OF LOGIC
//LOTS OF CODE
//YOUR N+1 PIECE OF LOGIC
//LOTS OF CODE
}
There are a few things that jump out that might be a problem.
- All this logic is buried in a trigger and is not reusable.
- It is very tough to test a specific piece of logic in the trigger. You basically have to call a DML statement to trigger the entire trigger.
So how do we fix that?
We would want to move the logic from the trigger itself into a utility or handler class.
Trigger ContactTrigger on Contact(before insert, after insert, before update, after update) {
if(trigger.isBefore){
if(trigger.isInsert){
ContactTriggerHandler.ContactBeforeInsert(trigger.new, trigger.newMap);
}
if(trigger.isUpdate){
ContactTriggerHandler.ContactBeforeUpdate(trigger.new, trigger.old, trigger.newMap, trigger.oldMap);
}
}
if(trigger.isAfter){
if(trigger.isInsert){
ContactTriggerHandler.ContactAfterInsert(trigger.new, trigger.newMap);
}
if(trigger.isUpdate){
ContactTriggerHandler.ContactAfterUpdate(trigger.new, trigger.old, trigger.newMap, trigger.oldMap);
}
}
}
Handler
public class ContactTriggerHandler {
public static void ContactBeforeInsert(list<Contact> newContacts, map<Id,Contact> newMap) {
myMethod1(newContacts, newMap);
myMethod2(newContacts, newMap);
}
public static void ContactBeforeUpdate(list<Contact> newContacts, list<Account> oldContacts, map<Id,Contact> newMap, map<Id,Contact> oldMap) {
myMethod3(newContacts, oldContacts, newMap, oldMap);
}
public static void ContactAfterInsert(list<Contact> newContacts, map<Id,Contact> newMap) {
myMethod2(newContacts, newMap);
myMethod4(newContacts, newMap);
}
public static void ContactAfterUpdate(list<Contact> newContacts, list<Account> oldContacts, map<Id,Contact> newMap, map<Id,Contact> oldMap) {
myMethod5(newContacts, oldContacts, newMap, oldMap);
}
public static void myMethod1(list<Contact> newContacts, map<Id,Contact> newMap){
//YOUR LOGIC
}
public static void myMethod2(list<Contact> newContacts, map<Id,Contact> newMap){
//YOUR LOGIC
}
public static void myMethod3(list<Contact> newContacts, list<Account> oldContacts, map<Id,Contact> newMap, map<Id,Contact> oldMap){
//YOUR LOGIC
}
public static void myMethod4(list<Contact> newContacts, map<Id,Contact> newMap){
//YOUR LOGIC
}
public static void myMethod5(list<Contact> newContacts, list<Account> oldContacts, map<Id,Contact> newMap, map<Id,Contact> oldMap){
//YOUR LOGIC
}
}
You have solved both of the problems mentioned above here. You can now reuse your code. You can call these public static methods from other places in order to reuse code. You can now also segment your testing and test individual smaller methods when testing your trigger, as you no longer have to make a DML call and run the whole trigger, you can just test individual methods.
Hopefully this handles some of your bulkification/best practices questions. There is actually quite a bit further you can go with optimizing but then we get into trigger frameworks and interfaces, but I think this is a decent start to some of the best practices when writing your triggers.
P.S. On a side note, this might be the kick I needed to actually start a blog as this turned out to be much lengthier than I originally planned.
Method declaration contains the variables not values. it should be
public static void InsertTrigger (List<QuoteLineItem> InsertedQuote, **Boolean flag**) {
}
Best Answer
Another good way to avoid recursion is highlighted in Chapter 6 of Dan Applemans's excellent book, Advanced Apex Programming. This particular example is around recursion when looking for a specific field change which is very common in many triggers.
As mentioned in @BarCotters answer, you generally run your trigger on very specific criteria. A change in a field can trigger certain logic in your trigger. If you look at the Order of Operations for triggers, you can see that any workflow rules and field updates based on those rules are run after the both before and after triggers have run. It runs however prior to the changes actually being committed to the DB, which is where this can cause problems when detecting field changes.
So lets say we are using a very simple example where we have a trigger on the Opportunity object that looks for opportunities that have been Won, and based on that it creates a new custom object record.
This trigger will work fine, and will create a new custom object when you close an Opportunity. It will work fine that is, assuming you have no WFR's that have field updates on the Opportunity Object.
Let's say now I had a workflow rule on the Opportunity that When an Opp is closed, it changes the CloseDate of the Opportunity to Today. (A fairly simple and common WFR that many admins may add).
That simple change now Breaks my trigger. This same trigger will now actually create 2 custom objects when my opportunity is closed. This is due to the fact that the WFR rule is now firing the triggers one final time.
This is how you would think the logic works
This is not how it works though, even though the opp has been updated, it has not yet been committed to the Database, so in the second run of the trigger it still see's the opp and just being closed like below
This is actually how it works
This is where Dan Appleman's solution comes in. He advises to use a mechanism that actually checks for the 'correct old value'. This would allow the second run of the trigger to detect the value that was set in the first run of the trigger.
With this change, now the WFR rule does not break our trigger. Only 1 custom object is created when the opp is closed.
I know this was longwinded, but I hope it helps. I would highly getting this book as this was only a few pages worth of goodness, and this book is jam packed with great knowledge that I think all SFDC developers should have.
Heres the link again.
http://advancedapex.com/