BeforeInsert.Finalizer
Runs once after the handler has processed every record of the chunk, with the records that qualified. Use it for checks across records, such as two new contacts with the same email.
Interface
apex
public class BeforeInsert {
public interface Finalizer {
void finalizeBeforeInsert(TriggerHandler.InsertRecords records);
}
}finalizeBeforeInsert(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 BeforeInsert.Populator, BeforeInsert.Finalizer {
public Boolean populateOnBeforeInsertWhen(TriggerHandler.InsertRecord record) {
return record.isNotBlank(Contact.Email);
}
public void populateOnBeforeInsert(TriggerHandler.InsertRecord record) {
record.put(Contact.Email, ((Contact) record.getNewSObject()).Email.trim().toLowerCase());
}
public void finalizeBeforeInsert(TriggerHandler.InsertRecords records) {
Set<String> emails = new Set<String>();
for (TriggerHandler.InsertRecord 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. A Validator's qualified records already carry an error, so its Finalizer sees only rejected records. The Skeleton normalizes emails in the action and rejects duplicates here.
- Reject on the row.
InsertRecordhas noaddError. Call((Contact) record.getNewSObject()).Email.addError(message)to keep the message on the field. - One chunk at a time. A 1,000-record insert runs in five chunks of 200. Duplicates in different chunks are never compared.
- No DML. If the Finalizer runs DML or publishes an event, the library throws, even with ContinueOnError.
- Skipped after a swallowed exception. With ContinueOnError, an exception in the predicate or the action skips the Finalizer for that chunk.
