Skip to content

BeforeUpdate.Finalizer

Runs once after the handler has processed the chunk, with the records that qualified. Use it for checks across records, such as duplicates within one save.

Interface

apex
public class BeforeUpdate {
    public interface Finalizer {
        void finalizeBeforeUpdate(TriggerHandler.UpdateRecords records);
    }
}
  • finalizeBeforeUpdate(records): called once per chunk, after this handler’s records, only if at least one record qualified. It receives only the qualified records.

Example

apex
public with sharing class ContactPopulator implements BeforeUpdate.Populator, BeforeUpdate.Finalizer {
    public Boolean populateOnBeforeUpdateWhen(TriggerHandler.UpdateRecord record) {
        return record.isChanged(Contact.Email) && record.isNotBlank(Contact.Email);
    }

    public void populateOnBeforeUpdate(TriggerHandler.UpdateRecord record) {
        record.put(Contact.Email, ((Contact) record.getNewSObject()).Email.trim().toLowerCase());
    }

    public void finalizeBeforeUpdate(TriggerHandler.UpdateRecords records) {
        Set<String> emails = new Set<String>();

        for (TriggerHandler.UpdateRecord record : records.getRecords()) {
            Contact contactRecord = (Contact) record.getNewSObject();

            if (!emails.add(contactRecord.Email)) {
                contactRecord.Email.addError('Another contact in this save has the same email.');
            }
        }
    }
}

Good to Know

  • Put it on a Populator. On a Validator, it receives only the records that Validator already rejected.
  • put works here. records.getRecords() returns UpdateRecords. On a Populator, a lookup the Finalizer re-points is loaded before the next handler runs.
  • Reject with the field form. UpdateRecord has no addError. Call ((Contact) record.getNewSObject()).Email.addError(message), as the Skeleton does.
  • Only this chunk. Other chunks of the same update are out of reach. A query returns their saved values.
  • No DML. If the Finalizer runs DML or publishes an event, the library throws, even with ContinueOnError.