+ Start a Discussion
venkateshyadav1243venkateshyadav1243 

Error Handling on batch apex class csv file.

Hi All,

Am trying to handle errors in my csv file before processing batch class
can any one please tell me how to handle errors in batch class and send error list to user email.
I written batch class for inset and update records its working fine,but now i have to handle few validation rule before insert/update and if any record is contain proper value ,i have to stop the batch process can one please help me how can i do this.
Below is my batch apex class.

global class CustomIterableBatchForGSSAccount implements Database.Batchable<String>,Database.Stateful{
global Map<Id, String> errorMap {get; set;}
    global Map<Id, SObject> IdToSObjectMap {get; set;}
    Public String CSVFile;
    Set<string> strset=new Set<string>();
    Map<string,id>  Offmap=new map<string,id>();
    Public  List<GSS_Split__c> Gsstoupload;
    Public  List<GSS_Split__c> Gsstoupdate;
    Public  List<GSS_Split__c> Gsssize;
    Public String Errormsgs;
    //Constructor to hold the uploaded CSV file
   
    global CustomIterableBatchForGSSAccount(String CSVFile){
        this.CSVFile= CSVFile;
         errorMap = new Map<Id, String>();
        IdToSObjectMap = new Map<Id, SObject>();
    }
   //Start Method
    global Iterable<String> start(Database.BatchableContext bc){
        return new CustomIterable(CSVFile);
    }
    //execute method
    global void execute(Database.BatchableContext bc,List<String> Scope){
    Gsstoupload = new List<GSS_Split__c>();
    Gsstoupdate = new List<GSS_Split__c>();
    Gsstoupload.clear();
    Gsstoupdate.clear();
   for(GSS_Split__c gss:[select name,Request_Number__c,Account_Index__c,Period_End_text__c,Period_Start_text__c,HQ__c,GRS_REPTYPE__c,GRS_PLATFORM__c,Territory__c,Region__c,WGSS_Perc__c,GSS_Perc__c,PeriodStart__c,Period_End__c,AX_login__c,Primary_AX__c from GSS_Split__c])
        {       
          Strset.add(gss.Request_Number__c);
          Offmap.put(gss.Request_Number__c,gss.id);
          System.debug('All GSS ACCOUNT OBJECT RECORDS'+gss);
        }
        List<String> inputvalues;
        try{       
            System.debug('**scope size**'+scope.size());

         
            for (Integer i=0;i<scope.size();i++)
            {
                inputvalues = new List<String>();
                //split the rows
                inputvalues = scope[i].split(',');
                if(Strset.contains(inputvalues[0]))
            {
                GSS_Split__c a = new GSS_Split__c(id=offmap.get(inputvalues[0]));
               
                //split the rows
               // inputvalues = scope[i].split(',');


            a.Request_Number__c=inputvalues[0];
            a.Account_Index__c= inputvalues[1];
            a.HQ__c= inputvalues[2];      
            a.GRS_REPTYPE__c= inputvalues[3];
            a.GRS_PLATFORM__c= inputvalues[4];
            a.Territory__c= inputvalues[5];
            a.Region__c= inputvalues[6];
            a.GSS_Perc__c= integer.valueof(inputvalues[7]);
            a.WGSS_Perc__c=integer.valueof(inputvalues[8]);
            a.Period_Start_text__c=inputvalues[9];
            a.Period_End_text__c=inputvalues[10];
            a.AX_login__c= inputvalues[11];
            a.Primary_AX__c= inputvalues[12];
            Gsstoupdate.add(a);
            }
             else{  
            GSS_Split__c a = new GSS_Split__c(id=offmap.get(inputvalues[4]));
            System.debug('gsss recordsssssss'+a);
            a.Request_Number__c=inputvalues[0];
            a.Account_Index__c= inputvalues[1];
            a.HQ__c= inputvalues[2];      
            a.GRS_REPTYPE__c= inputvalues[3];
            a.GRS_PLATFORM__c= inputvalues[4];
            a.Territory__c= inputvalues[5];
            a.Region__c= inputvalues[6];
            a.GSS_Perc__c= integer.valueof(inputvalues[7]);
            a.WGSS_Perc__c=integer.valueof(inputvalues[8]);
            a.Period_Start_text__c=inputvalues[9];
            a.Period_End_text__c=inputvalues[10];
            a.AX_login__c= inputvalues[11];
            a.Primary_AX__c= inputvalues[12];
            Gsstoupload.add(a);
           
            }
            }
          Savepoint sp = Database.setSavepoint();
            try{
        if(Gsstoupdate.size()>0)
        {
        System.debug('######## gsstoupdate'+Gsstoupdate);
update Gsstoupdate;
        }
        if(Gsstoupload.size()>0)
        {
         System.debug('######## gsstoupload'+Gsstoupload);
Database.insert(Gsstoupload,false);
        }
      
       
        }
        Catch (Exception e)
        {
Database.rollback(sp);
       
         System.debug('Exception--->'+e+'%%%'+e.getmessage());
        }   
            
        }Catch(Exception e){
            system.debug('Exception--->'+e+'%%%'+e.getmessage());
        }
       
    }
   
    global void finish(Database.BatchableContext bc)    {    }
}


Regards,
Venkatesh.
logontokartiklogontokartik
You can use the Database.SaveResult to get the ids of the successfully inserted records, and identify the ones that are not inserted. for the failed ones, you will not get id's hence If you are able to 

1. Key the CSV records with Unique numbers (like 1, 2, 3 ...)
2. Use the Lists to do the inserts (lists are generally ordered). 

You can basically know which record exactly failed. and then throw an exception. (when you throw an exception, everything in DB will be rolled back for that batch chunk.
Asif Ali MAsif Ali M
Follow the below steps to capture the errors:
  1. Process each row in CSV. If its valid (Based on your custom rules/validation logic) then add it to an validData array otherwise tag the record with custom error message and then add it to errorData
  2. If the count of errorData is zero then upsert validData otherwise process errorData and attach it to email
  3. Now read return result from upsert to capture the errors triggered by salesforce. If there is any failed record due to invalid data then entire batch will be rejected by salesforce.
  4. Now you have to read all data from scope and attach its corresponding error from return result then send it as email attachment
// STEP #1
for (Integer i=0;i<scope.size();i++) {

 	// Set object parameters from csv row scope[i]
 	// Custom validation rules to process scope[i]

 	if(valid) {
 		validData.add(myObj);
 	}
 	else {
 		errorData.add(myObj);
 	}
 }


// STEP #2
Database.UpsertResult[] upertResult;
if(errorData.size() > 0) {
        Schema.SObjectField f = YourObject.Fields.ID;  // any unique field will work
        upertResult = Database.upsert(validaData, f);
}
else{
      // Trigger email with errorData as attachment
}

//STEP #3 & #4

for(Integer idx = 0; idx < upsertResult.size(); idx++) {

    if(upsertResult[idx].isSuccess()) {

    	// scope[idx] will give the row data
    	// upsertResult[idx] will give the DB results for that csv row.

    } else {
             // read errors in upsertResult[idx].getErrors()

    }
     errorData.add(errorObj)
   
}

// Trigger email with errorData as attachment






Asif Ali MAsif Ali M
Above code is a pseudo code to give you an idea. Few things I would like to add.
  1. Generally any data loading tool will not stop the entire batch if one record fail.They generally track error on record level not on batch level
  2. If you want to have the same kind of functionality you you can use Boolean opt_allOrNone parameter in upsert method. By making this param false salesforce will only stop the error records it will continue with all success record in that batch. Please refere Database Method Syntax in below URL http://www.salesforce.com/us/developer/docs/dbcom_apex250/Content/apex_dml_upsert.htm
  3. For sending email with CSV attachment please refer https://developer.salesforce.com/forums/ForumsMain?id=906F000000090JcIAI

Hope this helps