+ Start a Discussion
Eric Blaxton 11Eric Blaxton 11 

How to skip trigger code based on record type

Hi and thanks in advance for any help.
Situation:
I wrote a web service to grab new cases from an external source.  That part works fine, BUT an after update trigger fires when uploading new cases and i get a ''Apex CPU time limit exceeded".  I thought if I skipped the Record Type it would skip the trigger code. 
This line causes the error is the for loop, which occurs before the RT check:
for (Case cse : Trigger.new){
trigger CompleteResolutionTimeMilestone on Case (after update) {
    
    for (Case cse : Trigger.new){        
        system.debug('cse.RecordTypeId ' + cse.RecordTypeId);
        if (cse.RecordTypeId != Schema.Sobjecttype.Case.getRecordTypeInfosByDeveloperName().get('Maintenance').getRecordTypeId()){
          if (UserInfo.getUserType() == 'Standard'){
        
           DateTime completionDate = System.now(); 
              List<Id> updateCases = new List<Id>();
              for (Case c : Trigger.new){
                  if (((c.isClosed == true)||(c.Status == 'Closed'))&&((c.SlaStartDate 
                        <= completionDate)&&(c.SlaExitDate == null)))
            updateCases.add(c.Id);
                       }
    if (updateCases.isEmpty() == false)
        milestoneUtils.completeMilestone(updateCases, 'Support Resolution Time', completionDate);
    }
        }// end if (cse.RecordTypeId !=
    }
}
Regards,
Eric
 
Best Answer chosen by Eric Blaxton 11
Andrew GAndrew G

A few reasons i can see for the possible time out.  See Notes in your code example
trigger CompleteResolutionTimeMilestone on Case (after update) {

    for (Case cse : Trigger.new){        
//we are now in a loop
        system.debug('cse.RecordTypeId ' + cse.RecordTypeId);
//the Schema call is now occuring for every record - adds time
        if (cse.RecordTypeId != Schema.Sobjecttype.Case.getRecordTypeInfosByDeveloperName().get('Maintenance').getRecordTypeId()){
//the getUserTYpe is being called every record
          if (UserInfo.getUserType() == 'Standard'){

//within the time frame of the trigger, why keep doing this call again?        
           DateTime completionDate = System.now(); 
//having this list declared within the loop will clear it every iteration
              List<Id> updateCases = new List<Id>();
//now for fun we seem to be invoking a loop of the loop - so if i have 10 records in my trigger, i am now looping 100 times
              for (Case c : Trigger.new){
                  if (((c.isClosed == true)||(c.Status == 'Closed'))&&((c.SlaStartDate 
                        <= completionDate)&&(c.SlaExitDate == null)))
            updateCases.add(c.Id);
                       }
//and we are still in the first loop, so we are call the milestones again and again
    if (updateCases.isEmpty() == false)
        milestoneUtils.completeMilestone(updateCases, 'Support Resolution Time', completionDate);
    }
        }// end if (cse.RecordTypeId !=
    }
}
a better solution where we just fix the setting of variables and remove the inner loop
trigger CompleteResolutionTimeMilestone on Case (after update) {
//declare my list to update once
List<Id> updateCases = new List<Id>(); 
//get the reference Record type once
String maintenanceRecordTypeId =     
Schema.Sobjecttype.Case.getRecordTypeInfosByDeveloperName().get('Maintenance').getRecordTypeId();
//work out what type of user we have once
Boolean isStandardUser;
if (UserInfo.getUserType() == 'Standard') {
   isStandardUser = true;
}
//set the completion date once
DateTime completionDate = System.now(); 

    for (Case cse : Trigger.new){        
        system.debug('cse.RecordTypeId ' + cse.RecordTypeId);
        if (cse.RecordTypeId != maintenanceRecordTypeId {
          if (isStandardUser){
                 if (((cse.isClosed == true)||(cse.Status == 'Closed'))&&((cse.SlaStartDate 
                        <= completionDate)&&(cse.SlaExitDate == null)))
            updateCases.add(c.Id);
           }
         }
      }
    if (updateCases.isEmpty() == false)
        milestoneUtils.completeMilestone(updateCases, 'Support Resolution Time', completionDate);
    }
}

now, arguably, we could speed up the trigger further by testing the running user first before we get into the loop - example below
trigger CompleteResolutionTimeMilestone on Case (after update) {
//declare my list to update once
List<Id> updateCases = new List<Id>(); 
//get the reference Record type once
String maintenanceRecordTypeId =     
Schema.Sobjecttype.Case.getRecordTypeInfosByDeveloperName().get('Maintenance').getRecordTypeId();
//work out what type of user we have once
Boolean isStandardUser;
if (UserInfo.getUserType() == 'Standard') {
   isStandardUser = true;
}

DateTime completionDate = System.now(); 

 if (isStandardUser){
    for (Case cse : Trigger.new){        
        system.debug('cse.RecordTypeId ' + cse.RecordTypeId);
        if (cse.RecordTypeId != maintenanceRecordTypeId {

                 if (((cse.isClosed == true)||(cse.Status == 'Closed'))&&((cse.SlaStartDate 
                        <= completionDate)&&(cse.SlaExitDate == null)))
            updateCases.add(c.Id);

         }
      }
    if (updateCases.isEmpty() == false)
        milestoneUtils.completeMilestone(updateCases, 'Support Resolution Time', completionDate);
    }
 }
}

I think that should put you on the right track


Regards

Andrew

p.s.  all code supplied as-is and uncompiled.
 

All Answers

Andrew GAndrew G

A few reasons i can see for the possible time out.  See Notes in your code example
trigger CompleteResolutionTimeMilestone on Case (after update) {

    for (Case cse : Trigger.new){        
//we are now in a loop
        system.debug('cse.RecordTypeId ' + cse.RecordTypeId);
//the Schema call is now occuring for every record - adds time
        if (cse.RecordTypeId != Schema.Sobjecttype.Case.getRecordTypeInfosByDeveloperName().get('Maintenance').getRecordTypeId()){
//the getUserTYpe is being called every record
          if (UserInfo.getUserType() == 'Standard'){

//within the time frame of the trigger, why keep doing this call again?        
           DateTime completionDate = System.now(); 
//having this list declared within the loop will clear it every iteration
              List<Id> updateCases = new List<Id>();
//now for fun we seem to be invoking a loop of the loop - so if i have 10 records in my trigger, i am now looping 100 times
              for (Case c : Trigger.new){
                  if (((c.isClosed == true)||(c.Status == 'Closed'))&&((c.SlaStartDate 
                        <= completionDate)&&(c.SlaExitDate == null)))
            updateCases.add(c.Id);
                       }
//and we are still in the first loop, so we are call the milestones again and again
    if (updateCases.isEmpty() == false)
        milestoneUtils.completeMilestone(updateCases, 'Support Resolution Time', completionDate);
    }
        }// end if (cse.RecordTypeId !=
    }
}
a better solution where we just fix the setting of variables and remove the inner loop
trigger CompleteResolutionTimeMilestone on Case (after update) {
//declare my list to update once
List<Id> updateCases = new List<Id>(); 
//get the reference Record type once
String maintenanceRecordTypeId =     
Schema.Sobjecttype.Case.getRecordTypeInfosByDeveloperName().get('Maintenance').getRecordTypeId();
//work out what type of user we have once
Boolean isStandardUser;
if (UserInfo.getUserType() == 'Standard') {
   isStandardUser = true;
}
//set the completion date once
DateTime completionDate = System.now(); 

    for (Case cse : Trigger.new){        
        system.debug('cse.RecordTypeId ' + cse.RecordTypeId);
        if (cse.RecordTypeId != maintenanceRecordTypeId {
          if (isStandardUser){
                 if (((cse.isClosed == true)||(cse.Status == 'Closed'))&&((cse.SlaStartDate 
                        <= completionDate)&&(cse.SlaExitDate == null)))
            updateCases.add(c.Id);
           }
         }
      }
    if (updateCases.isEmpty() == false)
        milestoneUtils.completeMilestone(updateCases, 'Support Resolution Time', completionDate);
    }
}

now, arguably, we could speed up the trigger further by testing the running user first before we get into the loop - example below
trigger CompleteResolutionTimeMilestone on Case (after update) {
//declare my list to update once
List<Id> updateCases = new List<Id>(); 
//get the reference Record type once
String maintenanceRecordTypeId =     
Schema.Sobjecttype.Case.getRecordTypeInfosByDeveloperName().get('Maintenance').getRecordTypeId();
//work out what type of user we have once
Boolean isStandardUser;
if (UserInfo.getUserType() == 'Standard') {
   isStandardUser = true;
}

DateTime completionDate = System.now(); 

 if (isStandardUser){
    for (Case cse : Trigger.new){        
        system.debug('cse.RecordTypeId ' + cse.RecordTypeId);
        if (cse.RecordTypeId != maintenanceRecordTypeId {

                 if (((cse.isClosed == true)||(cse.Status == 'Closed'))&&((cse.SlaStartDate 
                        <= completionDate)&&(cse.SlaExitDate == null)))
            updateCases.add(c.Id);

         }
      }
    if (updateCases.isEmpty() == false)
        milestoneUtils.completeMilestone(updateCases, 'Support Resolution Time', completionDate);
    }
 }
}

I think that should put you on the right track


Regards

Andrew

p.s.  all code supplied as-is and uncompiled.
 
This was selected as the best answer
ANUTEJANUTEJ (Salesforce Developers) 
Hi Eric,

>> https://salesforce.stackexchange.com/questions/48736/how-to-run-a-trigger-only-for-specific-record-types

>> https://developer.salesforce.com/forums/?id=906F0000000AprlIAC

I have found the above example that has scenarios that run a trigger for a specific record type you can check and change this to match this as per your use case.

Let me know if it helps you and close your query by marking it as solved so that it can help others in the future.  

Thanks.