3

I have set up my Case trigger with a single trigger and separate methods class to handle the activities.

I have added a Recursion Handler class to try and prevent the recursion happening, but this does not seem to be working properly at the moment, as when I manually edit a class it causes the error message to be displayed:

Error: Invalid Data. Review all error messages below to correct your data. Apex trigger WSC_CaseTrigger caused an unexpected exception, contact your administrator: WSC_CaseTrigger: execution of BeforeUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id 5005E000000uUQHQA2; first error: SELF_REFERENCE_FROM_TRIGGER, Object (id = 5005E000000uUQH) is currently in trigger WSC_CaseTrigger, therefore it cannot recursively update itself: []: Class.WSC_Case_Trigger_Methods.setCaseLOS: line 154, column 1

I am getting this error whether I put the call to the recursion handler around the specific method call that has the error linked to it or the entire trigger body of code.

Recursion Handler

    public class RecursiveTriggerHandler {
    public Static Boolean isFirstTime = true;

}

Trigger code

if (RecursiveTriggerHandler.isFirstTime) {
       RecursiveTriggerHandler.isFirstTime = false;
    if(Trigger.isBefore && Trigger.isUpdate) {
        List<Case> updateList = new List<Case>();


        for(Case caseObj : Trigger.New){
            if(caseObj.Status != 'New' && caseObj.Materially_Complete_Date__c != Null) {
                // call method in Case methods to keep case trigger class simple.
                updateList.add(new Case(id =caseObj.Id));

            }
            system.debug('No of cases to update'+updateList.size());
            WSC_Case_Trigger_Methods.setCaseLOS(updateList);
            }  

        }
    }

Relevant method of Trigger handler that is causing the exception

public static void setCaseLOS(List<Case>lstUpdate){
    WSC_Date_Functions date_Functions = new WSC_Date_Functions();
    System.debug('Start LOS updates');

     if(lstUpdate.size()>0){
         Integer daysBetween;
         Id MeteringRecordType = Schema.SObjectType.Case.getRecordTypeInfosByName().get('Metering').getRecordTypeId();
         //Id MDDRecordType = Schema.SObjectType.Case.getRecordTypeInfosByName().get('Maximum_Daily_Demand').getRecordTypeId();
        System.debug('updating case dates');
         for(case updates : lstUpdate) {
             if(updates.Market_Data_Accepted__c!=Null&&updates.Proposed_Date_to_Update_MO__c!=Null){                    

                updates.Market_Data_Response_Day__c = Date_Functions.Working_Days_Between(updates.Proposed_Date_to_Update_MO__c, updates.Market_Data_Accepted__c) ;
             }
             if(updates.Materially_Complete_Date__c != Null && updates.RecordTypeId==MeteringRecordType){
                 if(updates.Process_Reference__c=='B1'&&updates.Actual_Date_of_Exchange__c!=Null) {
                     daysBetween =  Date_Functions.Working_Days_Between(updates.Date_Quotation_Approved__c, updates.Actual_Install_Date__c); 
                     updates.Operational_Response_Days__c = daysBetween;
                     System.assert(daysBetween!=Null);
                     System.debug('Days between'+daysBetween);
                 }

             }

         }
       //update the cases
       update lstUpdate;

   }
  • 1
    Is that before update or after update trigger? Long story short, you can not execute update on same object in after update trigger which is in trigger – kurunve Jan 13 '17 at 15:24
  • The trigger has both before and after update methods in it, but looking at the best practices there should be one trigger per object so hard to avoid that - developer.salesforce.com/page/… – Dave Humm Jan 13 '17 at 15:30
  • well, be sure that your logic fire only once. In case if that is before trigger -- you do not need to execute update on record in trigger itself. if that is after -- you need to construct new sObject and update it (With id of existing one) or do job async (future/queueable) – kurunve Jan 13 '17 at 15:36
  • reread your code --> it is before, so remove update statement – kurunve Jan 13 '17 at 15:42
4

The simple solution is to follow the Apex Developer Guide recommendations on Triggers. Field updates belong in a before trigger and do not require a separate update call. When applying field updates in this way, you do not even need a static flag to block recursion, because you will not cause update trigger re-entry.

There are two types of triggers:

  • Before triggers are used to update or validate record values before they’re saved to the database.
  • After triggers are used to access field values that are set by the system (such as a record's Id or LastModifiedDate field), and to affect changes in other records, such as logging into an audit table or firing asynchronous events with a queue. The records that fire the after trigger are read-only.

So a more appropriate pattern would be:

Trigger

trigger CaseTrigger on Case (before insert, before update)
{
    if (trigger.isBefore)
    {
        if (trigger.isInsert)
        {
            CaseService.setSomeField(CaseService.applySomeFilter(trigger.new));
            // other methods
        }
        if (trigger.isUpdate)
        {
            CaseService.setSomeField(CaseService.applySomeFilter(trigger.new));
            // other methods
        }
    }
}

Service

public static List<Case> applySomeFilter(List<Case> records)
{
    List<Case> filtered = new List<Case>();
    //filter logic
    return filtered;
}
public static void setSomeField(List<Case> filtered)
{
    for (Case record : filtered)
    {
        record.Some_Field__c = someValue;
    }
}
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.