3

Wanted to see what the 'better' practice is or which would provide better performance.

Let's say I have a trigger like this:

trigger ProjectTrigger on Project__c (after update) {
    ProjectTriggerHandler.updateProjects(Trigger.newMap.keyset());
}

Now, in the handler class that needs to make an external callout, which would be the better option?

Option 1: (Here I am updating the collection that I get from SOQL query)

public class ProjectTriggerHandler {
    @future
    public static void updateProjects(Set<Id> projectIds) {
        List<Project__c> projects = [SELECT Id, Status__c FROM Project__c WHERE Id IN: projectIds];
        for(Project__c project : projects) {
            if(project.Status__c == 'Billable') {
                // Make SOAP callout and perform some logic
                project.Status__c = 'Billed'; 
            }
        }
        update projects;
    }
}

Option 2: (Here I am updating a new collection created to store only the records that pass the condition)

public class ProjectTriggerHandler {
    @future
    public static void updateProjects(Set<Id> projectIds) {
        List<Project__c> projects = [SELECT Id, Status__c FROM Project__c WHERE Id IN: projectIds];
        List<Project__c> projectsToUpdate = new List<Project__c>();
        for(Project__c project : projects) {
            if(project.Status__c == 'Billable') {
               // Make SOAP callout and perform some logic
               project.Status__c = 'Billed'; 
               projectsToUpdate.add(project);
            }
        }
        update projectsToUpdate;
    }
}

Lets say a batch process updates 100 project__c records and their statuses and now 5 of those records have a status__c == 'Billable'. Does Option 1 or Option 2 provide a better implementation of updating those 5 records?

6

Neither is best practice. Perform all field updates in the before context. Doing so does not consume any additional DML statements and avoids any risk of a recursive loop. Salesforce explicitly makes this recommendation in the Apex Developer Guide:

There are two types of triggers:

  • Before triggers are used to update or validate record values before they’re saved to the database.
  • After triggers are used to access field values that are set by the system (such as a record's Id or LastModifiedDate field), and to affect changes in other records, such as logging into an audit table or firing asynchronous events with a queue. The records that fire the after trigger are read-only.

Performing a field update clearly falls into the first category (updating record values).


As for your update question, neither approach is more efficient than simply including this filter in your query:

List<MyObject__c> records = [
    SELECT ... FROM MyObject__c WHERE ... AND Status__c == 'Billable'
];

If you filter at this level you will save CPU time, and it clearly does not add anything to incorporate another List.

  • Thanks, I actually edited my question, the example I made was a poor example and you are definitely right. If I were just trying to perform a field update in that context then your solution is definitely correct. – HHa Oct 23 '17 at 16:39
  • 2
    Please avoid completely changing your questions in ways that render posted answers meaningless. What often works better for preserving the context and adding to the community knowledge base is accepting the posted answer if it resolves what you asked, and asking a new question that better articulates what you meant to ask. – Adrian Larson Oct 23 '17 at 16:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.