2

I am getting error when I am trying to run my batch even I have applied the sort on list. Here is my batch:

global class DeleteRecordsBatch implements Database.Batchable<String>, Database.Stateful {
    global boolean bReRun = false; //will be used to determine if batch has to re-run in case there are more that 10K of records
    public Call_Plan_SCenario__c callPlanScenario{get;set;}
    public List<String> listOfObjectsRecordsToBeDeleted = new List<String>();
    public DeleteRecordsBatch(Call_Plan_SCenario__c newObj,List<String> newLst){
         callPlanScenario=newObj;
         system.debug('--newLst->'+newLst);
         for(String obj: newLst){
                listOfObjectsRecordsToBeDeleted.add(obj);
         }
        //system.debug('--bu--'+callPlanScenario.Team_Instance__r.Team__r.Name);
        system.debug('--lstrec--'+listOfObjectsRecordsToBeDeleted);
    }

    global Iterable<String> start(Database.BatchableContext ctx) {
        system.debug('--listOfObjectsRecordsToBeDeleted-->'+listOfObjectsRecordsToBeDeleted);
        return listOfObjectsRecordsToBeDeleted;
    }

    global void execute(Database.BatchableContext ctx, List<String> lstObjectName) {

        list<Sobject> lstDeleteRecords = new list<Sobject>();
        lstObjectName.sort();
        for(String strObjectName : lstObjectName) {

         system.debug('--strObjectName-->'+strObjectName);
            for(SObject objsObject : database.query('Select Id from ' + strObjectName)) {
                if(lstDeleteRecords.size() < 9998)
                    lstDeleteRecords.add(objsObject);

                else {
                    bReRun = true;
                    break;
                }
            } 

        }
       lstDeleteRecords.sort();
       delete lstDeleteRecords;
    }


    global void finish(Database.BatchableContext ctx) {
        if(bReRun) {
             Database.executebatch(new DeleteRecordsBatch(callPlanScenario,listOfObjectsRecordsToBeDeleted));
        }
       // Database.executeBatch(new ProcessScenarioBatch(callPlanScenario));
    }
}

And the parameter I am passing to batch are:

Call_Plan_Scenario__c  obj = [SELECT Id FROM Call_Plan_Scenario__c where Name='Senario1'];
List<String> lstOfObjects = new List<String>{'FF_TGTEXP_MRX_CALL_HYP_Q2_2017__c', 'NATPARA_MV_MDS_CBI_ALIGN_DTL__c', 'FF_COM_FLEX_FIELDS_NATPARA_TIER_Q2_2017__c'};

Id batchJobId = Database.executeBatch(new DeleteRecordsBatch(obj,lstOfObjects ), 200);
10

Because you wait until the execute() method to query for the records to delete, you are not utilizing the scope parameter (the second parameter of the Database.executeBatch method--'200' in your case) to limit the size of your batches. Because of this, you are attempting to delete too many records of too many types in a single call. If three different sObject types are being deleted, you are limited to deleting no more than 1,603 total records (explanation at end of this answer).

The reason for this is the combination of default trigger chunking (200 records at a time) and the additional chunking caused by hyprid sObject arrays. As per the docs:

For Apex, the chunking of the input array for an insert or update [or delete << mine] DML operation has two possible causes: the existence of multiple object types or the default chunk size of 200. If chunking in the input array occurs because of both of these reasons, each chunk is counted toward the limit of 10 chunks. If the input array contains only one type of sObject, you won’t hit this limit. However, if the input array contains at least two sObject types and contains a high number of objects that are chunked into groups of 200, you might hit this limit. For example, if you have an array that contains 1,001 consecutive leads followed by 1,001 consecutive contacts, the array will be chunked into 12 groups: Two groups are due to the different sObject types of Lead and Contact, and the remaining are due to the default chunking size of 200 objects. In this case, the insert or update operation returns an error because you reached the limit of 10 chunks in hybrid arrays. The workaround is to call the DML operation for each object type separately. - Apex Developer Guide

So, the 10-chunk limit will be hit if, for instance, 1,500 records of Type1object (8 chunks), 100 records of Type2object (9th chunk), and 201 records of Type3object (10th and 11th chunks) are deleted in the call at the end of your execute() method.

My recommendation would be to refactor the code to insert one sObject type at a time, to avoid the chunk limits imposed when performing DML on hybrid sObject arrays. Alternatively, a quick/dirty fix would be to change the line of code

if(lstDeleteRecords.size() < 9998)

to

 if(lstDeleteRecords.size() < 200*(11 - lstObjectName.size()) + lstObjectName.size())

This formula results in a 1,603-record cutoff point in your case where the names of 3 sObject types are passed in to the batch constructor. This limit is calculated based on a worst-case scenario where, for instance, just 1 Type1object record and 1 Type2object record are deleted (wasting an entire extra chunk to process just 1 record). We have 8 more chunks to use before we hit the 10-chunk limit, so we can insert up to 1,600 Type3object records, since that is 8 chunks of the maximum 200 records per chunk.

  • Not working it is still giving me same error – Jill_sfdc Feb 22 '17 at 7:18
  • Sorry, miscalculated the edge case; change 2001 to 1603. – Brent Bow Feb 22 '17 at 7:28
  • thanks it worked.. But can you explain why it was not working with 2001? – Jill_sfdc Feb 22 '17 at 7:37
  • 1
    @Jill_sfdc In case you ever call the class with more or fewer than 3 sObject names (in which case it will error out or process inefficiently, respectively), you should make the limit dynamic instead of simply '1603'. The formula to calculate the most records you can reliably delete in one DML call for n number of sObject types is 200(11-n) + (n-1). I have updated my answer a second time to account for this. – Brent Bow Feb 22 '17 at 15:01
  • 1
    Glad it helped you out, @SamKamensky. Jill_sfdc, is there a reason you do not include a WHERE clause in your query? You will need to add filters (or a LIMIT 50000) to your database.query string to avoid the SOQL row governor limit – Brent Bow Mar 31 '17 at 4:47

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.