Handle Returned Database Errors in Apex

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.

Util.cls

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());
}
}
}
view raw Util.cls hosted with ❤ by GitHub

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.

Join 72 other followers
Advertisements
Advertisements
  • Handle Returned Database Errors in Apex
    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.
  • Update Bulk Records with Mass Quick Action Button
    A mass quick action is a quick action that we can add to the search layout of an object. After creating a mass quick action, we can perform mass updates on up to 100 records in a list view.
  • Event-Driven Integrations Just Got Easier with the Pub/Sub API
    The Pub/Sub API provides a unified interface for publishing and subscribing to platform events such as real-time event monitoring and change data capture. Pub/Sub API efficiently publishes and delivers binary event messages in the Apache Avro format using gRPC and HTTP/2.
  • In and Not In Operators in Flows
    Salesforce’s Winter’23 release included this much-needed feature ↠ In and Not In operators in flow builder. With In and Not in operators, we can easily query the related data without writing a query inside the loop element.
  • Customize Login Experience using Login Flow
    A login flow can be used to personalize the login experience and integrate business processes with Salesforce authentication. Common use cases include displaying release/notice messages, collecting and updating user data at login, configuring multi-factor authentication, and integrating third-party strong authentication methods.
  • Platform Event Triggered Flow
    Platform event triggered flow launches when a platform event message is received. This auto-launched flow runs in the background. Similar to objects we can use the platform event field values from the platform event message by referencing the $Record global variable.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s