function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
si risi ri 

how to capture failed records in bacth class

Hi everyone!
              Need help, to capture failed records in batch class.Below  is my code, i am able to capture sucessfull records but unable to capture failed records.
global class updateOppSendPIQReport implements Database.Batchable<SObject>{
    
    global Set<Id> failureIdsSet;

    
    global Database.QueryLocator start(Database.BatchableContext BC)
    { 
        //Fetch records after opportunity stage is set to PIQ Complete
        return Database.getQueryLocator('SELECT ID, StageName__c, SendPIQReport__c, Opportunity__r.id FROM PIQ_Response__c where StageName__c = \'PIQ Complete\' or StageName__c = \'50-PIQ Complete\' ');
              
    }
    
    global void execute(Database.BatchableContext BC, List<PIQ_Response__c> scope){
        
        failureIdsSet = new Set<Id>();

        List<PIQ_Response__c> updatepiq = new List<PIQ_Response__c>();
        for(PIQ_Response__c piq :  scope){
            if(piq.SendPIQReport__c == False && piq.StageName__c == 'PIQ Complete'){
                
                String [] emailList = new List<String>();
                Set<Id> opId = new Set<Id>();
                
                opId.add(piq.Opportunity__r.id);
                //Fetch Opportunity Record
                Opportunity op = [select id, name, AccountID from Opportunity where Id=:opId];
                
                // DML statement
                Database.SaveResult[] srList = Database.update(scope, false);
                
                // Iterate through each returned result
                for (Database.SaveResult sr : srList) {
                    if (sr.isSuccess()) {
                        // Operation was successful, so get the ID of the record that was processed
                        System.debug('Successfull records****************************: ' + sr.getId());
                    }
                    else {
                        // Operation failed, so get all errors                
                        for(Database.Error err : sr.getErrors()) {
                            System.debug('The following error has occurred.');                    
                            System.debug(err.getStatusCode() + ': ' + err.getMessage());
                            System.debug('failed records**************************: ' + err.getFields());
                        }
                    }
                }
                //Fetch Email id of Account Manager
                List<AccountTeamMember> teamList = [ SELECT ID, TeamMemberRole,
                                                    User.Email
                                                    FROM AccountTeamMember
                                                    WHERE AccountID = :op.AccountID 
                                                    AND TeamMemberRole = 'Account Manager'];
                for(AccountTeamMember a1: teamList){
                    emailList.add(a1.User.Email);
                }
                //Fetch Email id of Sales Coordinator
                List<AccountTeamMember> teamList2 = [ SELECT ID, TeamMemberRole,
                                                     User.Email
                                                     FROM AccountTeamMember
                                                     WHERE AccountID = :op.AccountID 
                                                     AND TeamMemberRole = 'Sales Coordinator'];
                for(AccountTeamMember a2: teamList2){
                    emailList.add(a2.User.Email);
                }  
                 List<CustomUsers__c> cu1 = [select UserEmails__c from CustomUsers__c];
                
               
                for(CustomUsers__c u1:cu1){
                     list<string> templist = u1.UserEmails__c.split(',');
                    emailList.addAll(templist);
                     //emailList.add(u1.UserEmails__c); 
                                         system.debug('EmailList'+emailList);
                                     }
                
                String [] emailList2 = new List<String>();
                for (Integer i = 0; i<emailList.size(); i++) {
                    emailList2.add(emailList[i]);
                     system.debug('EmailList**'+emailList2);
                } 
                PIQCOntroller.sendPDf(piq.Id, emailList2);
                piq.SendPIQReport__c = True;
                updatepiq.add(piq);
            } 
        }
        update updatepiq;
        system.debug('updatepiq*******************'+updatepiq);
    }
    
    global void finish(Database.BatchableContext BC)
    {
    }
}
DheerajKumar@SalesforceDheerajKumar@Salesforce
Hi,

Impement the interface Database.Stateful to batch class. While processing for loop of Database.SaveResult in else part you need to add the failed record id to failureIdsSet.
 
// Adding failed record Id
failureIdsSet.add(sr.getId());
global class updateOppSendPIQReport implements Database.Batchable<SObject>, Database.Stateful {
    global Set<Id> failureIdsSet;
    
    global updateOppSendPIQReport() {

        failureIdsSet = new Set<Id>();
    }

    global Database.QueryLocator start(Database.BatchableContext BC)
    {
        // Start implementation
    }

    global void execute(Database.BatchableContext BC, List<PIQ_Response__c> scope){
        //..... Your Code
        //..... Your Code
		// DML statement
		Database.SaveResult[] srList = Database.update(scope, false);
		
		// Iterate through each returned result
		for (Database.SaveResult sr : srList) {
			if (sr.isSuccess()) {
				// Operation was successful, so get the ID of the record that was processed
				System.debug('Successfull records****************************: ' + sr.getId());
			}
			else {
				// Operation failed, so get all errors  

				// Adding failed record Id 
				failureIdsSet.add(sr.getId());
					
				for(Database.Error err : sr.getErrors()) {
				    
					System.debug('The following error has occurred.');                    
					System.debug(err.getStatusCode() + ': ' + err.getMessage());
					System.debug('failed records**************************: ' + err.getFields());
				}
			}
		}

       //..... Your Code
       //..... Your Code
    }
	 
	global void finish(Database.BatchableContext BC)
    {
		// Use failureIdsSet here
    }
	
}

Hit Kudos if this solve you problem and if this is what you are looking for then please mark it as a solution for other benefits.

Thanks
Dheeraj Kumar
si risi ri
Hi DheerajKumar,
                     I have tried your code, i amgeeting only Successfull records but unable to capture failed records.

 
DheerajKumar@SalesforceDheerajKumar@Salesforce
Hi,

I have tried with a sample code where I found like for failed record the getId() method is returing null value. So you can do one thing try to store scuess ids in set and then from scope you can match that which records are failed and add them into failure set.

You can refer this code and modify it as per your need:

Try below code :
 
Set<Id> successIdsSet = new Set<Id>();

// DML statement
Database.SaveResult[] srList = Database.update(scope, false);

// Iterate through each returned result
for (Database.SaveResult sr : srList) {
    if (sr.isSuccess()) {
        // Operation was successful, so get the ID of the record that was processed
        System.debug('Successfull records****************************: ' + sr.getId());
        successIdsSet.add(sr.getId());
    }
    else {
        // Operation failed, so get all errors
        System.debug('The following error has occurred.' + sr.getId());          
            
        for(Database.Error err : sr.getErrors()) {
            
            System.debug('The following error has occurred.');                    
            System.debug(err.getStatusCode() + ': ' + err.getMessage());
            System.debug('failed records**************************: ' + err.getFields());
        }
    }
}

// filtering the failed record ids

for(PIQ_Response__c obj : scope) {
    if(!successIdsSet.contains(obj.Id)) {
        failureIdsSet.add(obj.Id);
    }
}

Hit Kudos if this solve you problem and if this is what you are looking for then please mark it as a solution for other benefits.

Thanks
Dheeraj Kumar