0

I have a requirement to setup email to case and with specific business criteria. And I need to update case comments for every email record created on case. So, I check the checkbox of Thread-ID and My requirement is to update case comments.

I created a field on case called Last email.And run a workflow rule on email object with criteria as created and update above field with email text body.

To update case comments i wrote a trigger with after Insert and try to update case comments.But it's updating multiple times.

Apex Trigger

trigger ForARPU on case (after insert,after update,after delete,before insert,before update) 
{
    if(Trigger.isAfter && trigger.isUpdate) 
    {
        //Updating case comments
        AccountAssignment.CaseComments(Trigger.New);
    }
}

Apex Class

public class AccountAssignment {
    public static void CaseComments(List<Case> CaseTriggers) 
    {
        Case myCase = CaseTriggers[0];
        if (myCase.Last_email__c!= null) {
            String caseId= myCase.ID;
            CaseComment cc = new CaseComment(
                CommentBody=myCase.Last_email__c,parentID=caseId
            );
            insert cc;
        }
    }
}

I just changed my apex trigger working Fine as well apex class has been modified.And i modified my code to handle records in bulk records.But please provide your suggestions for best practices

trigger ForARPU on case (after insert,after update,after delete,before insert,before update) 
    {

if(Trigger.isAfter && trigger.isUpdate) 
   {    
//AccountAssignment.CaseComments(Trigger.New);
  AccountAssignment.CaseUpdation(Trigger.New,Trigger.OldMap);
}
}

Apex class

Public static void CaseUpdation(List<Case> CaseNew,map<Id, Case> CaseMap) {
        List<CaseComment> caseComments = new List<CaseComment>();
        for(Case c : CaseNew){
        if ((CaseMap == null || CaseMap.get(c.Id).Last_Email__c != c.Last_Email__c) && c.Last_Email__c != null)
        {
        caseComments.add(new CaseComment(CommentBody=c.Last_Email__c,parentID=c.Id));
        }
        insert caseComments;
        }

    }

Let me know

2

There are two common patterns to minimize recursion:

  • Static flags (covered in the already written answer)
  • Proper filtering (including changes to the filtered fields)

My recommendation here is that you filter so that you only act on records whose Last_email__c has changed.

List<Case> filtered = new List<Case>();
for (Case newRecord : newRecords)
{
    if (newRecord.Last_email__c != null &&
        (oldMap == null || newRecord.Last_Email__c != oldMap.get(newRecord.Id).Last_Email__c)
    ) filtered.add(newRecord);
}

Or if you install the Selector library, you can simply do:

List<Case> filtered = Select.Field.hasChanged('Last_email__c').andX(
    Select.Field.hasChanged('Last_Email__c', null)
).filter(newRecords, oldMap);

Then just act on this filtered list instead of the original.

  • Adrian -- I'm not super au fait with this library but don't you need a .filter(someListOfSobjects) method? – cropredy Dec 8 '16 at 0:05
1

Update can fire multiple times during a transaction and you are most likely running into this as an issue.

Aside from the "You should implement a Trigger Handler Framework" answer you can add a static property to limit the recursion in your current code:

Trigger

trigger ForARPU on case (after insert,after update,after delete,before insert,before update) 
{
    if(AccountAssignment.runOnce() && Trigger.isAfter && trigger.isUpdate) 
    {
        //Updating case comments
        AccountAssignment.CaseComments(Trigger.New);
    }
}

Class (adapted from sfdcFox answer here)

public class AccountAssignment {

    static Boolean flag = true;
    public static Boolean runOnce() {
        return flag && !(flag = false);
    }

    public static void CaseComments(List<Case> CaseTriggers) 
    {
        Case myCase = CaseTriggers[0];
        if (myCase.Last_email__c!= null) {
            String caseId= myCase.ID;
            CaseComment cc = new CaseComment(
                CommentBody=myCase.Last_email__c,parentID=caseId
            );
            insert cc;
        }
    }
}

You could place the runOnce code in a service / utility class if desired.

Basically this will only run the code once and on the second run of the update Trigger in the same transaction it will not enter the AccountAssignment.CaseComments method because the boolean will be false

  • 1
    Although honestly proper filters are a better solution than static flags most of the time. Just check if Last_email__c has changed in addition to checking if it is populated. – Adrian Larson Dec 7 '16 at 18:05
  • @AdrianLarson - Good point, Probably should add that as an answer as would be a better way to handle it and should be pointed out....All depends on the use case and a combination of both may be helpful to both reduce scope and SOQL usage – Eric Dec 7 '16 at 18:06
  • 1
    Sure, I'll add a separate answer. – Adrian Larson Dec 7 '16 at 18:07

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.