
While DML statements always throw exceptions when an operation fails for one of the records being processed and the operation is rolled back for all records, Database class methods can either throw exceptions and all records rolled back OR allow partial success for record processing.
Database class methods do not throw exceptions in the case of partial processing Instead, they return a list of errors that occurred on failed records.
The errors contain information about the failures and are returned by the Database class method. For insert and update operations, for example, a SaveResult object is returned. SaveResult, like all returned results, has a method called getErrors that returns a list of Database. Error objects, which represent any errors encountered.
⧔ Example
This example demonstrates how to retrieve the errors returned by a database.update operation. It updates contacts, one of which lacks the correct mailing city field value, and sets the second parameter to false: update(contactList, false); into database.update, This option enables partial processing.
↠ A batch class is written to copy/update the billing city of an account into the mailing city of its related contact.
↠ A validation rule is written on the contact object to prevent the update if the ‘Test’ keyword is provided in the mailing city.
As a Salesforce developer, you’ve been tasked with handling error records and logging the error details in the custom object so that users can see what happened and why a few contact records weren’t updated.
✓ Solution ↴
BatchUpdateContactMailingCity.cls
global with sharing class BatchUpdateContactMailingCity implements Database.Batchable<SObject>{ | |
global Database.QueryLocator start(Database.BatchableContext bc){ | |
String query = 'Select Id, BillingCity,(Select Id,Name, MailingCity from contacts) from Account'; | |
return Database.getQueryLocator(query); | |
} | |
global void execute(Database.BatchableContext bc, List<Account> accList){ | |
//list of contacts to update | |
List<Contact> conListToUpdate = new List<Contact>(); | |
for(Account acc: accList){ | |
for(Contact con: acc.contacts){ | |
con.MailingCity = acc.BillingCity; | |
conListToUpdate.add(con); | |
} | |
} | |
if(conListToUpdate.size()>0){ | |
List<Database.SaveResult> updateResults = Database.update(conListToUpdate,false); | |
List<SObject> objList = new List<SObject>(); | |
objList.addAll(conListToUpdate); | |
//call generic method to create the error log records | |
Util.createError(updateResults,objList,'Contact Update'); | |
} | |
} | |
global void finish(Database.BatchableContext bc){ | |
//add the finish code here | |
} | |
} |
How to get the Id of the record from Database.SaveResult where Update failed?
To get the Id of the failed record, we can use the List index Property. The index of the List we are updating and the result set retrieved are both the same.

public with sharing class Util { | |
/** | |
* @author SFDC Lessons | |
* @description Method to create the error log record | |
* @param List<Database.SaveResult> saveResults | |
* @param List<SObject> objectList | |
* @param String topic | |
* @return void | |
*/ | |
public static void createError(List<Database.SaveResult> saveResults, List<SObject> objectList, String topic){ | |
try{ | |
//error object list | |
List<Error_Log__c> errorList = new List<Error_Log__c>(); | |
for( integer i=0; i < saveResults.size(); i++ ){ | |
if (saveResults.get(i).isSuccess()) { | |
//add the code here if you want to do something in success case | |
}//error case | |
else if(! saveResults.get(i).isSuccess()){ | |
// Operation failed, so get all errors | |
Database.Error dbError = saveResults.get(i).getErrors().get(0); | |
system.debug('Failed record id: '+ (String) objectList[i].get('Id')); | |
String recordId, recordName = ''; | |
if(objectList.size()>0){ | |
recordId = (String) objectList[i].get('Id'); | |
recordName = (String) objectList[i].get('Name'); | |
} | |
Error_Log__c err = new Error_Log__c(); | |
err.Error_Message__c = dbError.getMessage(); | |
err.Stack_Trace__c = String.valueOf(dbError.getStatusCode()); | |
err.Record_ID__c = recordId; | |
err.Record_Name__c = recordName; | |
err.Topic__c = topic; | |
//add error in the list | |
errorList.add(err); | |
} | |
} | |
if (errorList.size()>0) { | |
insert errorList; | |
} | |
}catch(Exception e){ | |
System.debug('Exception has occured! ' + e.getMessage()); | |
} | |
} | |
} |
Summary
Handling errors in the partial insert/update is best practice. As a developer, you should design the solution in a way that you can respond quickly when businesses ask questions about any failure.