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
Praveen Jaswal 11Praveen Jaswal 11 

Apex Recursion Issue

I utilized below mentioned code in a class and used that class in a trigger to update a field at Account Level but it's giving me Trigger Recursion Error.( I know this can be done via simple workflow but want to understand how this can be achieved via apex)

(This code is from Apex Developers Guide. Here is the link:
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_dml_examples_insert_update.htm)


Account[] accts = new List<Account>();
for(Integer i=0;i<3;i++) {
Account a = new Account(Name='Acme' + i,
BillingCity='San Francisco');
accts.add(a);
}
Account accountToUpdate;
try {
insert accts;
// Update account Acme2.
accountToUpdate =
[SELECT BillingCity FROM Account
WHERE Name='Acme2' AND BillingCity='San Francisco'
LIMIT 1];
// Update the billing city.
accountToUpdate.BillingCity = 'New York';
// Make the update call.
update accountToUpdate;
} catch(DmlException e) {
System.debug('An unexpected error has occurred: ' + e.getMessage());
}
 
// Verify that the billing city was updated to New York.
Account afterUpdate =
[SELECT BillingCity FROM Account WHERE Id=:accountToUpdate.Id];
System.assertEquals('New York', afterUpdate.BillingCity);
ANUTEJANUTEJ (Salesforce Developers) 
Hi Praveen,

Can you try checking the trigger context in which it is running and see if there are any conflicts that might be causing the issue.

Let me know if changing the context of the trigger helps looking forward for your response.

Regards,
Anutej
AmitSoniAmitSoni
Please check if you are using the after insert or after update in trigger definition. Change this to before insert or before update. Hopefully this will resolve the recursion issue. If not then check that there is any workflow rule for Account object and take decision if this needs to be de-activated.

 
Andrew GAndrew G
Whilst seeing the context of the trigger would make it easier, if think briefly about what that code is doing, we get a clue to the recursion.

If we have that code inside a trigger for the account, what is happening is that the trigger for the account event will fire, and part of the code is to insert more Account records.   After the insert, we then update some of them. 

So lets talk insert trigger - 3 x accounts are inserted as part of the trigger and therefore the insert trigger fires again... ergo recursion.
And if we think update - there is an update event where we change the city which then invokes the trigger again.

Changing the context between before/after insert/update will not resolve the recursion issue as the code stands.


The code example as provided is more for a demonstration to be executed from "Execute anonymous" under the Developer console.  It is not the sort of code you want to stick inside a trigger for the Account object.

regards
Andrew
Praveen Jaswal 11Praveen Jaswal 11
@Anutej/@AmitSoni - I have already tried both after update & before update but i still get this error.

@Andrew G - As i wrote in my original query....I am only utilizing the update portion of the code....kindly ignore the Insert part.(I pasted the complete code and link as it's part of the standard documentation)
I think your "Execute Anonymous" explanation does make sense but what get's executed as on Dev Console should resonably work on instance as well, especially sObjects related code.
If this code shouldn't be used then can you please help with some sample code to update a field @ Account Level. Any help is really appreciated.
Andrew GAndrew G
@praveen
When i run code in the Developer console, it runs in the instance.  So that assumption is reasonable.  However, since triggers have context, that comes into play when running code.  Since a trigger will have "update" context, updating the same object type in the triggre will lead to recursion. Hence the original issue.

as for examples of triggers, they run mostly the same

an example where you wanted to update the Industry field for the Account when created if the Industry is blank.
trigger account_Testing on Account (before insert){

	if (Trigger.isBefore) {
	    for (Account account: Trigger.new) {
	    	if (String.isEmpty(account.Industry)) {
	    		account.Industry = 'Other';
	    	}
	    }
	}
}
 or
trigger account_Testing on Account (after insert){

	if (Trigger.isAfter) {
        List<String> accIds = new List<String>();
        for (Account account: Trigger.new) {
            if (String.isEmpty(account.Industry)) { 
                accIds.add(account);
            }
	    }
        if(accIds.size()>0) {
            List<Account> toUpdate = [SELECT Id, Industry FROM Account WHERE Id IN :accIds];
            for(Account acc : toUpdate){
                acc.Industry = 'Other';
            }
        }
	}
}

Both triggers above do the same fundamental thing, however, the before insert is better practice as it reduces the DMLs in the trigger.  It also takes less lines of code and is easier to read.

regards
Andrew