Skip to content

Record API ​

Every handler method that takes one record gets a TriggerTypes record interface. It wraps the new and old rows, the declared parents and the related records.

Record Interfaces ​

ContextRecordValidator error method getsCollection
BeforeInsertInsertRecordRejectableInsertRecordInsertRecords
AfterInsertInsertRecordInsertRecords
BeforeUpdateUpdateRecordRejectableUpdateRecordUpdateRecords
AfterUpdateUpdateRecordUpdateRecords
BeforeDeleteDeleteRecordRejectableDeleteRecordDeleteRecords
AfterDeleteDeleteRecordDeleteRecords
AfterUndeleteUndeleteRecordUndeleteRecords

All interfaces are nested in TriggerTypes.

Methods ​

MemberInsertRejectable InsertUpdateRejectable UpdateDeleteRejectable DeleteUndelete
getId(), getRelated(providerName)✓✓✓✓✓✓✓
getNewSObject(), getNewParent(lookupField)✓✓✓✓✓
getOldSObject(), getOldParent(lookupField)✓✓✓✓
put(field, value)✓✓
addError(error), addError(field, error)✓✓✓
value checks and record type checks✓✓✓✓✓✓✓
change detection✓✓

A missing member is a compile error, such as isChanged in an insert handler.

  • getId() is null in before insert.
  • getNewSObject() is the live row in before insert and before update. In the after contexts it is read-only.
  • getOldSObject() is read-only. Stop a delete with record.addError(…) in a BeforeDelete.Validator.
  • getNewParent(Contact.AccountId) returns the parent a ParentQuery loaded, or null. getOldParent reads PriorParentQuery. Pass the lookup field you declared. The row itself holds only the lookup Id: getNewSObject().Account is null.
  • put works only in before insert and before update. In after insert and after update it compiles but throws a FinalException that nothing can catch. Change saved records with a Writer.
  • addError(field, error) shows the error at record level on Name and address fields. The record is still rejected.

Value Checks ​

equals, doesNotEqual, isIn, isNotIn, contains, doesNotContain, startsWith, endsWith, isNull, isNotNull, isEmpty, isNotEmpty, isBlank, isNotBlank, isTrue, isFalse, greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo.

  • They read the new row. In the delete contexts they read the old row.
  • They see earlier changes. In before contexts, a value set by an earlier handler with put counts.
  • They never throw on null. Comparisons such as lessThan are false for null.
  • Case. equals and isIn ignore case for text. contains, startsWith and endsWith are case-sensitive.
  • 0 and false are values. They are not null, empty or blank.

Change Detection ​

Update contexts only: isChanged, isAnyChanged, areAllChanged, isChangedTo, isChangedToNotNull, isChangedFrom, isChangedFromTo.

  • isAnyChanged and areAllChanged take 2 to 5 fields or an Iterable<SObjectField>.
  • Text comparison ignores case. 'Doe' to 'DOE' is not a change.

Record Type ​

isRecordType(developerName) and isNotRecordType(developerName) compare by developer name, not label. They cost no SOQL.

  • Objects without record types throw a TriggerLibException.
  • A misspelled name is not caught. An unknown name resolves to no Id, so isRecordType is true for rows without a RecordTypeId, such as in-memory test rows, and false for all others.