1

when I try to run the code below I am getting this error: 'Too many DML rows: 10001'. The object that I am trying to update is one of the main object in the org. so it has multiples triggers, workflows, etc. and one API that runs all day long. I am trying to update 29000 records. can anybody please tell me why i am getting this error or if something is wrong with the code. I will appreciate any help!

Class code:

 public class updateNRProdObject{

  public Decimal Debug{ get; set; }     

  public void updateObject(){


  List<NRProducts__c> products = [SELECT id  FROM NRProducts__c WHERE  Active__c = true];
  Debug = products.size();

  for(NRProducts__c p : products){

     p.Active__c=false;

  }

  update products ;

 }
}
7

You cannot update more than 10000 records in a single transaction.

It looks like you may be doing this in a VF page so you will have to write your VF page to check the status of a batch every so often and then do what you require when it is completed. You can use <apex:actionPoller> in your page and run a method to query the AsyncApexJob object to see if the the batch has been completed or not.

Please note the examples may need some tweaking as I modified existing code to use your example. I may have missed something....

EXAMPLE PAGE

<apex:page controller="YOUR CONTROLLER" showHeader="true" sidebar="true" cache="false">

    <apex:outPutPanel layout="block" id="main_panel" rendered="{!!fatal_error}">

        <apex:outPutPanel layout="block" id="job_start" >

            <apex:outPutPanel layout="block" id="job_start_processing" rendered="{!AND(start_polling,NOT(job_is_done))}" styleClass="ctr">
                <div class="ctr">
                    <h1>In Progress - Please Wait</h1>
                    <br /><br />
                </div>

                <apex:image url="{!URLFOR($Resource.processing_small)}"/>
            </apex:outPutPanel>

            <apex:outPutPanel layout="block" id="job_start_button" rendered="{!!start_polling}" styleClass="ctr">           
                    <h1>Click 'Start Process' to begin</h1>
                    <br /><br />

                <apex:commandButton action="{!run_process}" value="Start Process" reRender="job_start,msgs"/>
            </apex:outPutPanel>


            <apex:actionPoller action="{!poll_for_completion}" reRender="job_start,job_stop,msgs" interval="5"/>

        </apex:outPutPanel>


        <apex:outPutPanel layout="block" id="job_stop" styleClass="ctr">

            <apex:outPutPanel layout="block" id="job_done" rendered="{!AND(job_is_done,ISBLANK(job_error_message))}">

                <div class="ctr">
                    <h1>Complete</h1>
                    <br /><br />
                </div>

                <apex:commandButton action="{!restart_page}" value="Reset Page" rerender="msgs"/>
            </apex:outPutPanel> 


            <apex:outPutPanel layout="block" id="job_error" rendered="{!AND(job_is_done,NOT(ISBLANK(job_error_message)))}">

                <div class="ctr">
                    <h1>Error</h1>
                    <br />
                    <p>Message: &nbsp; {!job_error_message}</p>
                    <br />
                </div>

                <apex:commandButton action="{!restart_page}" value="Reset Page" rerender="msgs"/>
            </apex:outPutPanel> 

        </apex:outPutPanel>


    </apex:outPutPanel> 
</apex:page>

EXAMPLE CONTROLLER

public with sharing class YOUR CONTROLLER NAME {

    private AsyncApexJob[] jobs;
    @TestVisible private ApexClass[] apex_class;
    @TestVisible private Map<ID,AsyncApexJob> previous_jobs;

    public boolean job_is_done  {get;set;}
    public boolean start_polling {get;set;}
    public boolean fatal_error{get;set;}
    public string job_error_message {get;set;}


    public YOUR CONTROLLER NAME(){


        job_is_done = false;

        apex_class = [Select ID, Name From ApexClass Where Name = 'CLASS NAME'];

        if(apex_class.isEmpty()) return;

        //get previous jobs - so we can kinda tell if ours has ran
        previous_jobs = New Map<ID,AsyncApexJob>([Select ApexClassID, JobType, MethodName, Status 
                                                From AsyncApexJob where JobType = 'BatchApex' 
                                                AND ApexClassID = :apex_class[0].id
                                                AND CreatedByID = :userInfo.getUserID()
                                                AND CreatedDate = LAST_N_DAYS:1]);



    }

    public void run_process(){


        try{
            example_Batch b = New example_Batch();
            database.executeBatch(b);
        }catch(exception e){
            job_error_message = e.getMessage();
        }
        //start_polling = true;
        job_is_done = true;



    }

    public void poll_for_completion(){

        if(job_is_done || start_polling == false) return;

        AsyncApexJob[] tmp = [Select ID, ApexClassID, JobType, MethodName, Status, ExtendedStatus 
                                                From AsyncApexJob 
                                                where JobType = 'BatchApex' 
                                                AND ApexClassID = :apex_class[0].id
                                                AND CreatedByID = :userInfo.getUserID()
                                                AND (ID NOT IN :previous_jobs.keySet())
                                                AND CreatedDate = LAST_N_DAYS:1
                                                AND (Status = 'Completed' OR Status = 'Failed')];


        if(!tmp.isEmpty() || test.isRunningTest()){
            job_is_done = true;

            if(!test.isRunningTest() && tmp[0].Status == 'Failed'){
                job_error_message = tmp[0].ExtendedStatus;
            }
        }





    }

    public pagereference restart_page(){

        pageReference pr = New PageReference('/apex/YOUR PAGE');
        pr.setRedirect(true);
        return pr;

    }




}

In order to do what you are wanting to do you will need to write a batch class to perform the updates. The code would look something like:

global class example_Batch implements Database.Batchable<sObject>{




    global Database.QueryLocator start(Database.BatchableContext BC) {

        String query = 'SELECT id  FROM NRProducts__c WHERE  Active__c = true';

        if(test.isRunningTest()){
            query += ' LIMIT 200';
        }

        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext BC, List<sObject> scope) {

        Decimal Debug = products.size();

          for(NRProducts__c p : (NRPProducts__c[])scope){

             p.Active__c=false;

          }


        database.update(scope,false);

    }

    global void finish(Database.BatchableContext BC) {

    }

}

Then to execute it you would use

example_Batch b = New example_Batch();
database.executeBatch(b);
  • Hello Eric, thank you for your response. I am using a vf Page with a single button. If I am not wrong i have to create this batch and execute the batch with the button making an instance. I've never used <apex:actionpoiler> so how do i check the status of the batch? Thank you in advance – Carlos Aug 27 '14 at 16:10
  • @Carlos - See updated answer – Eric Aug 27 '14 at 16:23
  • Eric, thank you so much man! i really appreciate your help!! – Carlos Aug 27 '14 at 16:25
  • 1
    @Carlos - The limit is only there for test methods. You cannot return more than 200 records in a batch during a test method so this will limit the results in cases where you have created more than 200 records. For non-test methods the query is not limited at all – Eric Aug 27 '14 at 17:41
  • 1
    Once. When you click the button the batch will run. It will be complete after all records in the query have been processed – Eric Aug 27 '14 at 18:45

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.