Skip to content

TriggerTypes.ParentFields ​

Lists the parent (lookup) fields a ParentQuery or PriorParentQuery add-on loads. Read the parents with record.getNewParent(…) or record.getOldParent(…).

Example

cls
public with sharing class ContactOwnerAlignmentWriter implements AfterInsert.Writer, AfterInsert.ParentQuery, AfterInsert.Bypassable {
    public static Boolean isBypassed = false;

    public Map<SObjectField, TriggerTypes.ParentFields> queryParentsOnAfterInsert() {
        return new Map<SObjectField, TriggerTypes.ParentFields>{ Contact.AccountId => TriggerTypes.ParentFields.with(Account.OwnerId).with('Owner', User.IsActive) };
    }

    public Boolean bypassOnAfterInsertWhen() {
        return ContactOwnerAlignmentWriter.isBypassed;
    }

    public Boolean writeOnAfterInsertWhen(TriggerTypes.InsertRecord record) {
        Contact newContact = (Contact) record.getNewSObject();
        Account account = (Account) record.getNewParent('Account');

        return account?.Owner?.IsActive == true && account.OwnerId != newContact.OwnerId;
    }

    public void writeOnAfterInsert(TriggerTypes.InsertRecord record, TriggerTypes.UnitOfWork unitOfWork) {
        Account account = (Account) record.getNewParent('Account');

        unitOfWork.toUpdate(new Contact(Id = record.getId(), OwnerId = account.OwnerId));
    }
}

The Map Key ​

The add-on method returns a Map<SObjectField, TriggerTypes.ParentFields>. The key is a lookup field on the trigger object, and the fields belong to the object it points to.

KeyRead back with
Contact.AccountIdgetNewParent('Account')
Contact.OwnerIdgetNewParent('Owner')
Invoice__c.Region__cgetNewParent('Region__r')

The relationship name is case-sensitive.

Methods ​

Signature

apex
ParentFields with(SObjectField field)
ParentFields with(String relationshipName, SObjectField field)

Both take up to five fields, or an Iterable<SObjectField>.

Example

apex
Contact.AccountId => TriggerTypes.ParentFields.with(Account.Name).with('Owner', User.Email)
  • Start from TriggerTypes.ParentFields. Every with returns the selection, so calls chain.
  • Grandparents. with('Owner', User.Email) loads the parent's owner. Read it as parentAccount.Owner.Email.

What Is Loaded ​

  • The declared fields and the Id. Reading any other field throws an SObjectException.
  • Declare what you read. Declarations of all handlers are merged, so a handler may see another handler's fields. If that handler is switched off, the field is gone. Declare every field in the handler that reads it.
  • Every record, qualified or not. Parents load before any predicate runs, so the query costs SOQL even when nothing qualifies.
  • Once per chunk. The parent queries run per chunk, never per record.
  • No sharing. Parents are read in system mode, so a handler can see records and fields the user cannot.
  • Polymorphic lookups are limited. For WhatId, WhoId or an OwnerId that can hold a queue, some parents come back null. In after insert, after update and after undelete, a field outside the Name object makes the query fail.