Monday, June 20, 2016

Synchronous Deletion more than 10000 rows.


Salesforce documentation says
  • "Total number of records processed as a result of DML statementsApproval.process, or database.emptyRecycleBin is 10,000"
  • "Total number of DML statements issued 150" 

It does not mean you can delete/insert/update/upsert a row maximum of 9999 in a group up to 150 times. It is cumulative that mean the number of records gets added as a single list. Which means as soon you start your DML process or enter inside your apex function your session starts and then with each DML it keeps adding rows to check the count is less than 10,000 or not. 

For Example:

public void delTest(){
  List<Account> a; // say of size 9000
  List<Account__c> a1; // Say list of 2000;
  // Now if we fire 
  delete a;
  delete a1;
  // We are going to receive too many DML rows as the total count of DML rows is 
  // 9000 + 2000 = 11,000. 
}  

To overcome this issue we have two possible solution 

  1. To implement a batch/future/remote [asynchronous] process to delete 
  2. Or we need to check the total size of the DML rows and go back to the VF page and initiate same function until all desired record got deleted.
Now we can chain batch-process from the finish method and can pass "this" parameter to the same batch process and can make it stateful so that it can remember the records on which DML was performed. 
But if we want synchronous operation actionFunction is the only operation which can help up to do more DML.
<apex:page>
   <apex:form>
     <apex:actionFunction name="delTest" action="{!delTest}" rerender="scriptPanel"                                                onComplete="CheckAllDone();" />
     <apex:actionFunction name="allDone" action="{!allDone}" rerender="page" />
   </apex:form>
   <apex:outputPanel id="scriptPanel" >
     <script>
        function CheckAllDone(){
           var hasMore = {!hasMore} ;
           if(hasMore){
                delTest();
           }
           else{
              allDone();
           }
        }  
     </script>
   <apex:outputPanel/>
</apex:page>

public Boolean allDone {get;set;} {allDone false; }
public Boolean hasMore {get;set;} {hasMore =false; }
public void delTest(){
  allDone  = false;
  hasMore = false;
  List<Account> a; // SOQL to get records
  List<Account__c> a1; // SOQL to get records
  List<sObject> objList = new List<sObject>();
  for(Account temp : a){
   if(objList.size() >= 9999){
     hasMore = true;
     break;
   }
      objList.add(temp);
  }
  for(Account__c temp : a1){
   if(objList.size() >= 9999){
     hasMore = true;
     break;
   }
      objList.add(temp);
  }
  // do check for sizes here if size > 10,000 limit the DML and prepare batches
  delete objList;
  if(hasMore == false){
   allDone = true;
  }
}  
public void allDone(){
 // do nothing;
}

//====================== batch Class ===========================

global class BatchDelete implements Database.Batchable<sObject>,Database.Stateful{
  // to remember List Of dml rows.
   global Set<Id> sobjList = new Set<Id>();
   global Boolean allDone = false;  
   // constructor 
   global BatchDelete (){
   }
   global Database.QueryLocator start(Database.BatchableContext batchContext) { 
     // do sqol to get data 
     String query = 'Your SOQL here';
     return Database.getQueryLocator(query); 
   }
   global void execute(Database.BatchableContext BC, list<sObject> forDML){
      // add here and manipulate your dmlList.
      // add to the set sobjList 
      // set allDone to true if all dml completed
   }
   global void finish(Database.BatchableContext BC){
      // chain the batch job
      if(!allDone){
          Database.executeBatch(this); 
      }
      else{
         // fire a trigger or email to start another process.
      } 
   }
}

Tips on passing Salesforce AI Associate Certification

  🌟 Motivation to Pursue the Salesforce AI Associate Certification 🌟 The world of technology is in a state of perpetual evolution, and on...