4

I'm working on a cleanup of some older apex code, and I've noticed two distinct patterns being used to handle errors when saving records.

One uses a try-catch block to try to update the records, and displays the exception to the page if any is caught.

try {
    update accounts;
} catch (Exception e) {
    ApexPages.addMessages(e);
}

The other uses the Database class to get a result, and then iterates over the results of a insert/update operation and displays the error onto the page.

Database.SaveResult result = Database.Update(accounts, true); 

if (!result.isSuccess()) {
    for (Database.Error err:result.getErrors()) {
        ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.ERROR, err.getMessage()));
    }
}

Which of these two patterns is more efficient?

2
  • 2
    efficient in which terms? Commented Mar 2, 2016 at 15:03
  • 2
    I only use Database.Update with allOrNothing = false when I'm allowing for partial successes; otherwise I use the try-catch
    – cropredy
    Commented Mar 2, 2016 at 17:26

3 Answers 3

7

I wouldn't necessarily say that one is more "efficient" than the other. It's more a matter of what the author wanted the code to accomplish. The first method will only add one message to send to a page while the latter will add a message for each record that isn't saved.

What do you want to accomplish with your code and convey to the user? Is your code in a trigger, a class of some kind, or is it in a controller for a visualforce page? The location of the code would impact the choice one might make. I don't believe the answer to your question is merely one of efficiency.

7
  • Ive heard that using a try/catch can be more expensive than other methods, which led me to asking this question. The code itself is a controller for a visualforce page, as the goal of these snippets, as far as I understand the author's intent, was merely to get the message onto the page as quickly as possible. I guess the question would come down to "Should I use a try/catch or not?". Commented Mar 2, 2016 at 15:17
  • 1
    @battery.cord Unless you're working with very large datasets, which is hard to do through a Visualforce page, it's unlikely that there'd be any difference in execution time. Using the database methods for DML with the second parameter AllOrNone set to true (and passing a list of sobjects) means that it won't suppress any exceptions...which would lead to needing to use try/catch anyway. tl;dr just use try/catch
    – Derek F
    Commented Mar 2, 2016 at 15:26
  • 1
    If you use the database result method, a try-catch method isn't necessary. I don't know that a try-catch is "more expensive". You'd have to be more specific in telling us what "expensive" means to you. I can't see where one would be slower than the other unless it's an extremely large save with a lot of errors being sent to the page. Even then, the difference in page load would seem to be miniscule unlss you exceeded the viewstate limits and likely overwhelm the viewer with the error messages.
    – crmprogdev
    Commented Mar 2, 2016 at 15:28
  • 2
    Agreed with the general sentiment in the comments. SFDC is slow and inefficient to begin with. Optimizing on ms doesn't really do much. The biggest culprits for inefficiencies can be found in googling best practices. Stay away from the biggest inefficiencies and then you can just focus on logic. So I 2nd @crmprogdev, its all a matter of what you want to accomplish. Commented Mar 2, 2016 at 19:27
  • 3
    ApexPages.addMessages can add many messages - see example in my answer.
    – Keith C
    Commented Mar 2, 2016 at 19:59
6

In addition to the addMessages I also create an exception record, because if It isn't an error that should be a hard stop I still may want to know what broke. This requires a new custom object, I call it Exception

public with sharing class BusinessException extends Exception
{
public static void recordError(String fileName, String methodName, String errorMessage)
{
        Exceptions__c newException = createError(fileName, methodName, errorMessage);
        insertError(newException);          
 }

private static Exceptions__c createError(String fileName, String methodName, String errorMessage)
{
    Exceptions__c result = new Exceptions__c();
    result.FileName__c = fileName;
    result.MethodName__c = methodName;
    result.SystemError__c = errorMessage;

    return result;
}

private static void insertError(Exceptions__c oopsey)
{
    try
    {
        insert oopsey;
    }
    catch(DMLException dmlError)
    {

    }
   }
}

Then when you build your Try/Catch, whatever what you decide on you can capture that failure in your new object. I do a ton of Callouts and would be lost without this pattern

 try
    {     
       //something      
    }
    catch(QueryException error)
    {

        BusinessException.recordError('File_Name', 'Method Name', error);
    }   
4
  • 5
    Plural object names! Boo! Still +1 for the logging concept.
    – Adrian Larson
    Commented Mar 2, 2016 at 19:17
  • I actually do something very similar, which has helped greatly in tracking down some of the rarer exceptions that crop up from time to time. Commented Mar 3, 2016 at 14:51
  • Instead of DML I go for Database.insert(OopseyList, false) in the insertError method
    – Jarvis
    Commented Mar 3, 2016 at 18:24
  • Can we bulkify this one? Such that recordError is called without an Insert call and insertError is called at the end of each class and trigger.
    – Jarvis
    Commented Mar 4, 2016 at 13:59
5

This test page:

<apex:page controller="MyController">
    <apex:pageMessages/>
    <apex:form>
        <apex:commandButton value="Save" action="{!save}"/>
    </apex:form>
</apex:page> 

and controller:

public with sharing class MyController {
    public PageReference save() {
        try {
            insert new Contact[] {
                    new Contact(),
                    new Contact(),
                    new Contact(Phone = '12345678901234567890123456789012345678901234567890'),
                    new Contact(Birthdate = Date.newInstance(1, 1, 0)),
                    new Contact(Birthdate = Date.newInstance(1, 1, 0)),
                    new Contact(AssistantName = 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ')
                    };
        } catch (DmlException e) {
            ApexPages.addMessages(e);
        }
        return null;
    }
}

produces this result:

screen shot of multiple messages

So as the plural addMessages method name hints the try/catch/ApexPages.addMessages does a good job of capturing the important information when there are multiple errors.

In terms of efficiency, it is a simple pattern to code correctly so it is efficient in that sense.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .