global Database.QueryLocator start(Database.BatchableContext BC)
    return Database.getQueryLocator([SELECT id, 
                                    (SELECT id, Status, Description,
                                    FROM Cases WHERE Status = 'Open') 
                                    FROM Account]);

global void execute(Database.BatchableContext BC, List<Account> scope)
    List<Case> CaseToClose = new List<Case>();
    for(Account accVar : scope)
        For(case caseVar: accVar.cases)
    if(caseVar.DCA_Status__c == 'Withdrawal' && caseVar.Description == null &&
                                        (caseVar.Status_Reason_Code__c == '100 - PAID IN FULL' ||  
                                         caseVar.Status_Reason_Code__c == '220 - RECALLED TO JVCO' ||
                                         caseVar.Status_Reason_Code__c == '230 - ACCOUNT CLOSED BY JVCO'))
            caseVar.Status = 'Closed';
    else if(caseVar.DCA_Status__c == 'On Hold' && caseVar.Description == null &&
                                        (caseVar.Status_Reason_Code__c == '370 - REQUEST TO PAY' ||
                                         caseVar.Status_Reason_Code__c == '380 - PROMISE TO PAY'))
            caseVar.Status = 'Closed';

    update CaseToClose;

The basic change needed is to move the update CaseToClose; outside of both loops as you only need to do one update of all the Cases. There is no double loop in the sense of wasted cycles relating one collection to another.

But it would be good to also change the start method so that it is returning the Case objects in batches not the Account objects in batches with an indeterminate number of child Case objects each that could cause governor limits to be hit.


The changed start query would be just this (as you are not using any Account fields):

return Database.getQueryLocator([
        SELECT id, Status, Description,
                JVCO_DCA_Status__c, JVCO_Status_Reason_Code__c 
        FROM Case
        WHERE Status = 'Open'

and you will need to change the execute too to match.

| improve this answer | |
  • So if I move out the update CaseToClose; outside of both loops it won't be considered as bad practice and won't be a problem with governor limits? – Newbee May 25 '18 at 10:59
  • update outside loop only is best practice... – Sagar Hinsu May 25 '18 at 11:00
  • @RenceOicer The key point is to avoid your code failing because it runs into any of these governor limits. Moving the update will avoid hitting the "Total number of DML statements issued" limit, but you are still at risk of hitting the "Total number of records retrieved by SOQL queries" limit unless you restructure as suggested; whether you do or not depends on the number of cases per account etc. But it's best to be sure a limit won't be hit. – Keith C May 25 '18 at 11:05
  • I added the start method can you show me the way it is supposed to be? – Newbee May 25 '18 at 11:54
  • @RenceOicer See the PS in the answer. – Keith C May 25 '18 at 13:06

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.