public String CloudThoughts{ get; set;}
Trigger development (apologies to Roy Rogers' horse) is not done on a daily basis by a typical Force.com Developer.
In my case, Trigger development is similar to using regular expressions (regex) in that I often rely on documentation and previously developed code examples to refresh my memory, do the coding, then put it aside for several weeks/months.
I decided to create a more fluent Trigger template to address the following challenges and prevent me from repeatedly making the same mistakes:
The solution was to create a mega-Trigger that handles all events and delegates them accordingly to an Apex trigger handler class.
You may want to customize this template to your own style. Here are some design considerations and assumptions in this template:
References: Apex Developers Guide - Triggers Steve Anderson - Two interesting ways to architect Apex triggers
AccountTrigger.trigger
trigger AccountTrigger on Account (after delete, after insert, after undelete, after update, before delete, before insert, before update) { AccountTriggerHandler handler = new AccountTriggerHandler(Trigger.isExecuting, Trigger.size); if(Trigger.isInsert && Trigger.isBefore){ handler.OnBeforeInsert(Trigger.new); } else if(Trigger.isInsert && Trigger.isAfter){ handler.OnAfterInsert(Trigger.new); AccountTriggerHandler.OnAfterInsertAsync(Trigger.newMap.keySet()); } else if(Trigger.isUpdate && Trigger.isBefore){ handler.OnBeforeUpdate(Trigger.old, Trigger.new, Trigger.newMap); } else if(Trigger.isUpdate && Trigger.isAfter){ handler.OnAfterUpdate(Trigger.old, Trigger.new, Trigger.newMap); AccountTriggerHandler.OnAfterUpdateAsync(Trigger.newMap.keySet()); } else if(Trigger.isDelete && Trigger.isBefore){ handler.OnBeforeDelete(Trigger.old, Trigger.oldMap); } else if(Trigger.isDelete && Trigger.isAfter){ handler.OnAfterDelete(Trigger.old, Trigger.oldMap); AccountTriggerHandler.OnAfterDeleteAsync(Trigger.oldMap.keySet()); } else if(Trigger.isUnDelete){ handler.OnUndelete(Trigger.new); } }
AccountTriggerHandler.cls
public with sharing class AccountTriggerHandler { private boolean m_isExecuting = false; private integer BatchSize = 0; public AccountTriggerHandler(boolean isExecuting, integer size){ m_isExecuting = isExecuting; BatchSize = size; } public void OnBeforeInsert(Account[] newAccounts){ //Example usage for(Account newAccount : newAccounts){ if(newAccount.AnnualRevenue == null){ newAccount.AnnualRevenue.addError('Missing annual revenue'); } } } public void OnAfterInsert(Account[] newAccounts){ } @future public static void OnAfterInsertAsync(Set<ID> newAccountIDs){ //Example usage List<Account> newAccounts = [select Id, Name from Account where Id IN :newAccountIDs]; } public void OnBeforeUpdate(Account[] oldAccounts, Account[] updatedAccounts, Map<ID, Account> accountMap){ //Example Map usage Map<ID, Contact> contacts = new Map<ID, Contact>( [select Id, FirstName, LastName, Email from Contact where AccountId IN :accountMap.keySet()] ); } public void OnAfterUpdate(Account[] oldAccounts, Account[] updatedAccounts, Map<ID, Account> accountMap){ } @future public static void OnAfterUpdateAsync(Set<ID> updatedAccountIDs){ List<Account> updatedAccounts = [select Id, Name from Account where Id IN :updatedAccountIDs]; } public void OnBeforeDelete(Account[] accountsToDelete, Map<ID, Account> accountMap){ } public void OnAfterDelete(Account[] deletedAccounts, Map<ID, Account> accountMap){ } @future public static void OnAfterDeleteAsync(Set<ID> deletedAccountIDs){ } public void OnUndelete(Account[] restoredAccounts){ } public boolean IsTriggerContext{ get{ return m_isExecuting;} } public boolean IsVisualforcePageContext{ get{ return !IsTriggerContext;} } public boolean IsWebServiceContext{ get{ return !IsTriggerContext;} } public boolean IsExecuteAnonymousContext{ get{ return !IsTriggerContext;} } }