Skip to content

AfterUndelete

Runs in after undelete, after records are restored from the Recycle Bin. Change other records with a Writer or start async work with a Dispatcher.

Roles

  • Writer: create, update or delete other records through a unit of work.
  • Dispatcher: make one bulk call per chunk, such as enqueueing a Queueable.

Add-ons

  • ParentQuery: load parent (lookup) fields before the first handler runs; read them with getNewParent.
  • RelatedQuery: query children, siblings or any other records once per chunk; read them with getRelated.
  • OwnUnitOfWork: give the handler its own unit of work, committed right after it. Writer only.
  • Bypassable: skip this handler for the whole chunk when a condition holds.
  • Finalizer: run once after this handler’s records, with the records that qualified.
  • ContinueOnError: log and swallow this handler’s exceptions, so the save goes on.

Register

Implement TriggerOrchestrator.AfterUndelete on the orchestrator and return the handlers from afterUndeleteHandlers(). List order is run order. The trigger must list after undelete and call TriggerOrchestrator.run(new ContactTriggerOrchestrator()).

apex
public with sharing class ContactTriggerOrchestrator implements TriggerOrchestrator.AfterUndelete {
    public List<AfterUndelete.Handler> afterUndeleteHandlers() {
        return new List<AfterUndelete.Handler>{ new ContactWriter(), new ContactDispatcher() };
    }
}

Good to Know

  • No Validator. Salesforce has no before undelete event. To block a restore, call record.getNewSObject().addError(…) from a Writer or Dispatcher and list that handler first. The record stays in the Recycle Bin.
  • The restored row is read-only. Writing to getNewSObject() throws a FinalException that no catch stops. To change the record, register unitOfWork.toUpdate(new Account(Id = record.getId(), …)). That fires BeforeUpdate and AfterUpdate again.
  • Lookups hold only the Id. ((Contact) record.getNewSObject()).Account is null. Declare a ParentQuery and read record.getNewParent('Account').
  • Only the top-level record's trigger runs. Salesforce restores cascade-deleted children with their parent, but runs only the parent's after undelete trigger. Handle the children from the parent's handlers.
  • Called per chunk. afterUndeleteHandlers() runs for every chunk of up to 200 records. Restoring 1,000 records means 5 runs and 5 Dispatcher calls.