+ Start a Discussion
Jake GmerekJake Gmerek 

Interesting problem

I have a custom object with a "Set Default" Checkbox to indicate that that record is the default record for another process.  Obviously I only want one default record at a time.  I am writing a trigger to set all the other records checkbox to false when a new or updated records checkbox is set to true.  Here is my Code:

 

 

trigger SetDefault on Workflow_Types__c (before insert, before update) {
    
    List<Workflow_Types__c> wt = new List<Workflow_Types__c>([Select id, default__c from Workflow_Types__c]);
    Integer size = wt.size();
    for (Workflow_Types__c w: Trigger.new){
        if (w.Default__c == True){
            for (Integer i = 0; i < wt.size(); i++){
                if (wt[i].id != w.id){
                    wt[i].Default__c = False;
                    //update wt[i];
                }else{
                    Workflow_Types__c temp = wt.remove(i);
                    system.assertEquals(w.id, temp.id);
                    system.assertEquals(wt.size(), size-1);
                }
            }
        }
    }
    update wt;
    
}

 The problem is that even though I am trying to remove the record that calls the trigger and the assertions are passed for some reason it is still trying to recursively update the calling record when I call update wt, and gives me an error.  If I uncomment the line //update wt[i]; and comment the other update it does work, but I am afraid of possibly hitting governor limits by putting the DML statement in the for loops.  Any ideas would be appreciated.

 

Thanks

 

Edit: I have determined that the behaviour I described only happens when there are only two records in the object.  If I add more objects I have no problems

 

Best Answer chosen by Admin (Salesforce Developers) 
Ankit AroraAnkit Arora

You are updating Workflow_Types__c in trigger which get triggered before update and insert of Workflow_Types__c. You are creating a scenario which is causing cascading. You need to rethink over your approach to update Workflow_Types__c.

 

Thanks

Ankit Arora

Blog | Facebook | Blog Page

All Answers

theitdeptrockstheitdeptrocks

trigger SetDefault on Workflow_Types__c (before insert, before update) {
    
    List<Workflow_Types__c> wt = new List<Workflow_Types__c>([Select id, default__c from Workflow_Types__c where Default__c = true]);
    
    for (Workflow_Types__c w: Trigger.new){
        if (w.Default__c == True){
            for (Workflow_Types__c wts:wt){
                if (wts.id != w.id){
                    wts.Default__c = False;

                }
            }
        }
    }
    update wt;
    
}

Jake GmerekJake Gmerek

That is a better way to write the trigger, however it has not solved the issue.  I think that the trigger is upset cause it is recursively calling itself, but how would i bypass that?

theitdeptrockstheitdeptrocks

Is there an error message it is throwing?

Ankit AroraAnkit Arora

You are updating Workflow_Types__c in trigger which get triggered before update and insert of Workflow_Types__c. You are creating a scenario which is causing cascading. You need to rethink over your approach to update Workflow_Types__c.

 

Thanks

Ankit Arora

Blog | Facebook | Blog Page

This was selected as the best answer
theitdeptrockstheitdeptrocks

Does this work?

 

trigger SetDefault on Workflow_Types__c (before insert, before update) {
    
    List<Workflow_Types__c> wt = new List<Workflow_Types__c>([Select id, default__c from Workflow_Types__c where Default__c = true]);

if wt.size() >1{
    
    for (Workflow_Types__c w: Trigger.new){
        if (w.Default__c == True){
            for (Workflow_Types__c wts:wt){
                if (wts.id != w.id){
                    wts.Default__c = False;

                }
            }
        }
    }
    update wt;

}
    
}

Jake GmerekJake Gmerek

@ Anit - I did rethink and I think I got it working.  I still need to write a test class for it but use testing seemed to work.

 

I added a test case so that my last section looks like this:

 

 

if(needsUpdate){
        update wt;
    }

 

 

needsUpdate gets set if wt gets updated at all, but only then.  This way it avoids the cascade effect.  Thanks for all you help guys.