AfterDelete.Writer
Registers writes to other records on a unit of work after records are deleted. Remove orphans, leave a task on the former parent or recompute a parent from the records that remain.
Interface
apex
public class AfterDelete {
public interface Writer extends Handler {
Boolean writeOnAfterDeleteWhen(TriggerHandler.DeleteRecord record);
void writeOnAfterDelete(TriggerHandler.DeleteRecord record, TriggerHandler.UnitOfWork unitOfWork);
}
}writeOnAfterDeleteWhen(record): called once per record in the chunk. Returntrueto write for the record.writeOnAfterDelete(record, unitOfWork): called right after its predicate returns true, with this Writer’s unit of work.
Example
apex
public with sharing class ContactWriter implements AfterDelete.Writer {
public Boolean writeOnAfterDeleteWhen(TriggerHandler.DeleteRecord record) {
return record.isNotNull(Contact.AccountId);
}
public void writeOnAfterDelete(TriggerHandler.DeleteRecord record, TriggerHandler.UnitOfWork unitOfWork) {
unitOfWork.toInsert(new Task(WhatId = ((Contact) record.getOldSObject()).AccountId, Subject = 'Review contact'));
}
}apex
public with sharing class ContactRemovalTaskWriter implements AfterDelete.Writer, AfterDelete.PriorParentQuery {
public Map<SObjectField, TriggerHandler.ParentFields> queryParentsOnAfterDelete() {
return new Map<SObjectField, TriggerHandler.ParentFields>{ Contact.AccountId => TriggerHandler.ParentFields.with(Account.OwnerId) };
}
public Boolean writeOnAfterDeleteWhen(TriggerHandler.DeleteRecord record) {
return record.isNull(Contact.MasterRecordId) && record.getOldParent('Account') != null;
}
public void writeOnAfterDelete(TriggerHandler.DeleteRecord record, TriggerHandler.UnitOfWork unitOfWork) {
Contact contactRecord = (Contact) record.getOldSObject();
Account accountRecord = (Account) record.getOldParent('Account');
unitOfWork.toInsert(new Task(WhatId = contactRecord.AccountId, OwnerId = accountRecord.OwnerId, Subject = 'Contact removed: ' + contactRecord.LastName));
}
}Good to Know
- Never register the deleted row. An update of it fails the commit with
ENTITY_IS_DELETED, and a delete withSELF_REFERENCE_FROM_TRIGGER. - Read the old row, not SOQL. SOQL no longer finds the deleted row. Read its values from
getOldSObject(), which is read-only. - Merge losers qualify. Skip them with
record.isNull(Contact.MasterRecordId), as the second tab does. - When writes commit. By default all Writers share one unit that commits once, after the last handler. With OwnUnitOfWork or ContinueOnError, the Writer's unit commits right after it.
- Writer wins. A class that also implements
AfterDelete.Dispatcherruns only as a Writer.
Test
apex
@IsTest
static void writeOnAfterDeleteWhenQualifiesContactWithAccount() {
// Setup
Contact oldContact = new Contact(AccountId = new TriggerHandler.RandomIdGenerator().get(Account.SObjectType));
// Test
Boolean qualifies = new ContactWriter().writeOnAfterDeleteWhen(new TriggerHandler.TriggerRecord(null, oldContact));
// Verify
Assert.isTrue(qualifies, 'A contact with a former account should qualify.');
}