2

I have the below code, which works, but I'm a little concerned that I'm calling a method in a loop, which performs a query. Basically, the trigger looks to see if the field Auto_Close_Reopen__c is set to true, and if so, it will clone a new case automatically. I have a separate workflow controlling that field that checks several criteria. Once the object(case) has been cloned, I don't want to have it cloned again, so the issue I was concerned about is having someone go back into the record and then saving it, which would kick off the trigger again.

Would there be a better way to construct the code?

Trigger code:

trigger AutoClosedCloneCase on Case (after update) {
List<Case>cloneList = new List<Case>();
for (Case originalCase: Trigger.new){

    if (originalCase.Auto_Close_Reopen__c == true)
    {
        //Separate method that will clone the case objects
        sObject originalSObject = (sObject) originalCase;
        List<sObject> originalSObjects = new List<sObject>{originalSObject};      
        List<sObject> clonedSObjects = SupportCloneFields.cloneObjects(
                                  originalSobjects,
                                  originalSobject.getsObjectType());                                 
        Case clonedCase = (Case)clonedSObjects.get(0);

        //Update new case values
        cloneList.add(clonedCase);
        clonedCase.Status = 'New';
        clonedCase.Auto_Closed__c = false;
        clonedCase.Auto_Close_Reopen__c = false;
        clonedCase.Time_Spent__c = null;          
        clonedCase.Count_of_Reopens__c = null;
        clonedCase.In_Progress_Delay__c = null;
        clonedCase.ParentId = originalCase.ID;  

        //Update original case in separate method
        SupportCloneFields.SetCloneFalse(originalCase.Id);                            
    }                               
}

try {
    insert cloneList;
    } catch(DMLException e) {   
   System.debug('The following exception has occurred: ' + e.getMessage()); 
}    
}

Method:

public static void SetCloneFalse(Id caseID) {
    Case c = [SELECT id FROM Case WHERE ID = :caseID];
    c.Auto_Close_Reopen__c = false;

    try {
        update c;             
        } catch(DMLException e) {   
        System.debug('The following exception has occurred: ' + e.getMessage()); 
        }
}

Thanks,

Andy

  • is Auto_Close_Reopen__c field can be edited by users?in any case, if the field is edited back to true by user(or by a back end code) definitely the trigger will be fired. Not clear what is the concern you are having. Anyway this can lead to a query limit exception when doing a mass update(like from Data Loader) since you are querying inside a loop – highfive Mar 7 '14 at 18:47
  • No, it can't be edited by users, but if they edit a case that has been closed and then save it again, the trigger will kick off, which I'm trying to prevent. I don't want it to trigger again, so I'm trying to figure ways around that or find a different approach. I originally had an incoming email kick off the trigger, but there is some other backend code that was interfering, so now I have the Workflow updating the Auto_Close_Reopen__c checkbox. – ajl7519 Mar 7 '14 at 18:58
  • Querying and updating per object in a trigger generally runs you into governor limits. The general solution is to move to set oriented queries and update so only one query and one DML is done no matter how many objects the trigger is handling. – Keith C Mar 7 '14 at 19:43
2

In this scenario its best to check if the value has been changed as part of the transaction, otherwise you will execute your code whenever a record is edited that has the Auto_Close_Reopen__c field set to true. You can check this by comparing the field from the record in trigger.old(Map) with the field from the record in trigger.new(Map).

You'd also do better to have a version of setCloneFalse() that takes a list of case ids, otherwise you will hit governor limits when your trigger is processing more than 100 records. It should be fairly straightforward to fix both of these, something like:

// list of case ids to update
List<Id> caseIds=new List<Id>();

for (Case originalCase: Trigger.new){

    // only execute the code if the flag has changed to true

    if ( (originalCase.Auto_Close_Reopen__c == true) && 
         (!Trigger.oldMap.get(originalCase.id).Auto_Close_Reopen__c==true) )
    {
        //Separate method that will clone the case objects
        sObject originalSObject = (sObject) originalCase;
        List<sObject> originalSObjects = new List<sObject>{originalSObject};      
        List<sObject> clonedSObjects = SupportCloneFields.cloneObjects(
                                  originalSobjects,
                                  originalSobject.getsObjectType());                                 
        Case clonedCase = (Case)clonedSObjects.get(0);

        //Update new case values
        cloneList.add(clonedCase);
        clonedCase.Status = 'New';
        clonedCase.Auto_Closed__c = false;
        clonedCase.Auto_Close_Reopen__c = false;
        clonedCase.Time_Spent__c = null;          
        clonedCase.Count_of_Reopens__c = null;
        clonedCase.In_Progress_Delay__c = null;
        clonedCase.ParentId = originalCase.ID;  

        // add case id to the list of those to update
        caseIds.add(originalCase.Id);
    }                               
}

SupportCloneFields.SetCloneFalse(originalCase.Id);                            

new method:

public static void SetCloneFalse(List<Id> caseIDs) {
    List<Cases> toUpdate=[SELECT id FROM Case WHERE ID in :caseIDs];
    for (Case cs : toUpdate)
    {
       cs.Auto_Close_Reopen__c = false;
    }

    try {
        update toUpdate;             
        } catch(DMLException e) {   
        System.debug('The following exception has occurred: ' + e.getMessage()); 
        }
}
  • You know, I pretty much had the same thing. I ended up adding a flag field to be on the safe side, so it checks that for false before the trigger goes and then updates (using your example). I have this field hidden and out of sight. I tested it in the Sandbox and it seems to be working okay. Kind of getting Apex a bit more. I come C# and Visual Studio and developing for the cloud is definitely a bit more challenging, but getting used to ti. – ajl7519 Mar 10 '14 at 19:02
1

If you have an after update trigger, when a field/fields are edited that trigger will fire which is the way that it needs to be. But in the trigger since you are checking for the relevant field, this is ok. One possible issue is it's not a good idea to update the same instance inside an after update trigger. Because it cause to fire the trigger again and again(even the maximum deep can be reached). But here I don't think it will be a problem since you are checking for the field.

  • Thanks, but I have another issue with order execution as I mistakenly though trigger after updates fired after workflows, which they do not, so the workflow I'm using to call the trigger will not work. Reason, I had the checkbox is because the on email trigger it was kicking off a brand new case instead of cloning the original, as where the on case trigger kicks off the clone correctly. – ajl7519 Mar 7 '14 at 19:51
  • It do fire triggers if the workflows have field updates. Check [salesforce.com/us/developer/docs/apexcode/Content/… steps 9 and 10. Ideally it should fire a trigger when there is a field update – highfive Mar 7 '14 at 20:10
  • Actually, I think it's working correctly, but still creating new creating blank cases instead of cloning the case with details. This only happens when I use Email Message criteria in the workflow or trigger. When I don't use Email Message criteria it clones correctly. I wish I knew more about Salesforce to know where to track down these issues. – ajl7519 Mar 7 '14 at 20:26
  • As per my understanding this should work unless otherwise your use cases don't have any misleading scenarios. Try using System.debug() to drill down.(Hope you have already done it) – highfive Mar 8 '14 at 3:52

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.