0

I have noticed that many of the Apex triggers in my org update records even when there are no substantive changes to those records. For instance, consider a trigger that sets field values on an object based on some criteria, then makes an update call to commit those values to the database. In practice, this trigger commonly assigns the exact same values that already exist on the record, so it ends up making a DML call when no DML is needed -- or including more records in an update list than need to be included.

To improve performance across the org, I would like to retrofit all my triggers to avoid these kinds of inefficiencies, probably via some type of utility method. Has anyone else has tackled this kind of problem, who can recommend an efficient pattern to address it?

Note: I understand that it is possible to check existing field values one by one, but to me this seems like an unacceptably verbose approach.

3
  • I would still suggest to use the most basic approach and check if relevant field(s) were changed per each process. You can build utility method that will check if field was changed, but if you will build too complex utility mehcanizem only to get all fields/values in advance, it might became inefficiency by itself. You can build something basic like isFieldChanged(fieldName, sobjectNew, sObjectOld)
    – Liron C
    Mar 5 at 6:05
  • Considering the answer from @sfdcfox, what would be the relative advantage of the approach you describe? Mar 7 at 18:19
  • Just simplicity. Using utility approach as suggested is also fine, just make sure it is not too complex and cover most of your use cases.
    – Liron C
    Mar 8 at 5:25

1 Answer 1

5

You can do this with a couple of maps. I guess a nice convenience method would help.

public static void getDiffs(sObject[] recordsToUpdate, Map<Id, sObject> preValues, Map<Id, sObject> postValues) {
  for(Id recordId: postValues.keySet()) {
    sObject postValue = postValues.get(recordId);
    if(preValues.get(recordId) != postValue) {
      recordsToUpdate.add(postValue);
    }
  }
}

Which then lets you write something like:

Map<Id, Account> oldValues = new Map<Id, Account>([
  SELECT ... FROM ... WHERE ...
]);
Map<Id, Account> newValues = oldValues.deepClone();
// Now, manipulate newValues as you'd like
// Then
Account[] recordUpdates = new Account[0];
getDiff(recordUpdates, oldValues, newValues);
update recordUpdates;

When you use != to compare sObjects, it checks all fields at once, so by setting up specific "old values" to compare to, you can check many, even hundreds, of fields at once.

Note that I specifically use an "out parameter" syntax because of various language limitations. For example, you can't use upsert on a List<sObject>, so we can select a more specific ("concrete") sObject type.

2
  • We learn something from your answer @sfdcfox :)
    – metasync
    Mar 5 at 2:18
  • Excellent -- I didn't know that detail about sObject equality. I look forward to testing this out! Mar 7 at 18:15

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.