Find your content:

Search form

You are here

Handling Record Errors in a Batch Process

 
Share

How does one handle individual record errors in a Batch Process?

Tried the following example below, but once I iterate through wlist after the batch has completed (checking the job status through an apex:actionPoller), the wlist contains no errors, even though several have occurred.

//Calling Class
MyBatchClass job = new MyBatchClass(wlist);
Id jobId = Database.executeBatch(job);
//iterate through wlist to look for record erros

//Batch class
global class MyBatchClass implements Database.Batchable<SObject>,Database.Stateful{

  global List<MyWrapper> wlist {get;set;}
  global Integer currentIndex {get;set;}

  public MyBatchClass(List<MyWrapper> wlist){
     this.currentIndex = 0;
         this.wlist = wlist;
  }

  global Iterable<sObject> start(Database.BatchableContext bc){
    List<MyObject__c> olist = new List<MyObject__c>();
    for(MyWrapper w : rewardPoints){
      olist.add(w.obj);
    }
    return olist;
  }

  global void execute(Database.BatchableContext bc, sObject [] objects){
    for(Database.SaveResult sr : Database.insert(objects,false)){
      if(!sr.success){
        wlist.get(currentIndex).errorMessage = sr.getErrors().get(0);  
      }
      currentIndex++;
    }
  }

  global void finish(Database.BatchableContext bc){}
}

Attribution to: James Loghry

Possible Suggestion/Solution #1

You can only access wlist in the finish method of the batch class. You will not be able to access it by waiting for the batch job to finish and then getting job.wlist.

If you are trying to run the batch job from a visualforce page and provide detailed information about the errors on the page when the job completes you have three ways of doing this.

  1. Save wlist to an object in salesforce and then query for it when the job completes. You could include the batch job id in the object to separate results from different jobs.
  2. put wlist in a static variable in your finish method and then access that static variable from your controller.
  3. Pass in your controller to MyBatchClass and update a MyWrapper list variable that resides in your controller. I haven't tested this but I THINK it should work.

Here's some sample code for the first option:

global class MyBatchClass implements Database.Batchable<SObject>, Database.Stateful
{

  global List<MyWrapper> wlist {get;set;}
  global Integer currentIndex {get;set;}

  public MyBatchClass(List<MyWrapper> wlist){
     this.currentIndex = 0;
         this.wlist = wlist;
  }

  global Iterable<sObject> start(Database.BatchableContext bc){
    List<MyObject__c> olist = new List<MyObject__c>();
    for(MyWrapper w : rewardPoints){
      olist.add(w.obj);
    }
    return olist;
  }

  global void execute(Database.BatchableContext bc, sObject [] objects){
    for(Database.SaveResult sr : Database.insert(objects,false)){
      if(!sr.success){
        wlist.get(currentIndex).errorMessage = sr.getErrors().get(0);  
      }
      currentIndex++;
    }
  }

  global void finish(Database.BatchableContext bc)
  {
      list<Batch_Error__c> errors = new list<Batch_Error__c>();
      for(MyWrapper w : wlist) errors.add(new Batch_Error__c(error=w.errormessage));
      insert errors;
  }
}

Attribution to: Greg Grinberg
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/609

My Block Status

My Block Content