Menu Bar

Tuesday 4 June 2013

Two interesting ways to architect Apex triggers.....

Two interesting ways to architect Apex triggers

I’ve been writing Apex triggers for a while, and recently I ran across two ways to architect triggers that are different from how I used to do things. Both methods have one main benefit–they push all your logic to your classes, and allow the trigger to do just one job–invoke code on data change.
Here’s a trigger architected the first way:
 
01.trigger MyTrigger on MyObject__c (before insert, before update, after insert, after update) {
02. 
03.if(trigger.isBefore){
04.if(trigger.isInsert){
05.MyObjectInsertBefore myInsertBefore = new MyObjectInsertBefore(Trigger.new);
06.}
07.if(trigger.isUpdate){
08.MyObjectUpdateBefore myUpdateBefore = new MyObjectUpdateBefore(Trigger.old,Trigger.new);
09.}
10.}
11. 
12.if(trigger.isAfter){
13.if(trigger.isInsert){
14.MyObjectInsertAfter myInsertAfter = new MyObjectInsertAfter(Trigger.new);
15.}
16.if(Trigger.isUpdate){
17.MyObjectUpdateAfter myUpdateAfter = new MyObjectUpdateAfter(Trigger.old,Trigger.new);
18.}
19.}
20.}
As you can see from the trigger, all that we’re doing is invoking the correct class based on the starting criteria–are we an insert or an update, and are we before or after? We’ve got a separate class for each of the four cases.
Here’s what two of those classes might look like:
01.public class MyObjectInsertBefore {
02. 
03.//create your variables and data structures
04. 
05.//constructor
06.public MyObjectInsertBefore(){
07. 
08.}
09. 
10.//constructor accepting a list of myObjects
11.public MyObjectInsertBefore(MyObject__c[] myObjects){
12.//call whatever methods you need to get the job done
13.someMethod(myObjects);
14..
15..
16..
17.}
18.}
 
01.public class MyObjectUpdateBefore {
02. 
03.//create your variables and data structures
04. 
05.//constructor
06.public MyObjectUpdateBefore(){
07. 
08.}
09. 
10.//constructor accepting a list of myObjects
11.public MyObjectUpdateBefore(MyObject__c[] myOldObjects,MyObject__c[] myNewObjects){
12.//call whatever methods you need to get the job done
13.someMethod(myOldObjects,myNewObjects);
14..
15..
16..
17.}
18.}
Key to making this efficient is to have shared methods in a MyObjectUtil class, so that similar operations can be reused across your classes.
Here’s a trigger invoked the second way:
01.trigger MyTrigger on MyObject__c (before insert, before update, after insert, after update) {
02. 
03.public enum triggerAction {beforeInsert, beforeUpdate, afterInsert, afterUpdate}
04. 
05.if(Trigger.isInsert && Trigger.isBefore){
06.MyObjectClass process = new MyObjectClass(Trigger.new, Trigger.old, triggerAction.beforeInsert);
07.}
08.if( Trigger.isAfter && Trigger.isInsert ){
09.MyObjectClass process = new MyObjectClass(Trigger.new, Trigger.old, triggerAction.afterInsert);
10.}
11.if(Trigger.isUpdate && Trigger.isBefore){
12.MyObjectClass process = new MyObjectClass(Trigger.new, Trigger.old, triggerAction.beforeUpdate);
13.}
14.if( Trigger.isAfter && Trigger.isUpdate ){
15.MyObjectClass process = new MyObjectClass(Trigger.new, Trigger.old, triggerAction.afterUpdate);
16.}    
17.}
This trigger sends the old and new sets over to a class and passes the way that this was invoked via an enum value (look up enum in the Apex docs if you haven’t used them–I had to). There is only one class, and then the class sorts out what should happen based on the data:
 
01.public class MyObjectClass {
02. 
03.public MyObjectClass()
04.{
05.}
06. 
07.public enum triggeredAction {beforeInsert, beforeUpdate, afterInsert, afterUpdate}
08. 
09.public MyObjectClass(MyObject__c[] myObjects, MyObject__c[] myOldObjects, triggeredAction ta)
10.{  
11. 
12.// BEFORE INSERT
13.if (ta==triggeredAction.beforeInsert)
14.{
15.someBeforeInsertMethod()
16.}
17. 
18.// BEFORE UPDATE
19.if (ta==triggeredAction.beforeUpdate)
20.{
21.someBeforeUpdateMethod();
22.}
23. 
24.// AFTER INSERT
25.if (ta==triggeredAction.afterInsert)
26.{
27.someAfterInsertMethod()
28.}
29. 
30.// AFTER UPDATE
31.if (ta==triggeredAction.afterUpdate)
32.{
33.someAfterUpdateMethod();
34.}
35. 
36.}
37.}
You can see that you’re basically accomplishing the same thing–getting the class to invoke the right methods based on the invocation, but that we’re doing it in two different ways. In the first example, we’ve got a proliferation of classes, and each class is very simple. In the second example, we’ve got one class that is more complex as it has to handle many types of invocation.
I ran across the second example in the spring and really liked it. Then I ran across the first example last month and now it’s my favorite. I’m going to try to write new triggers that way and see how they go.
Thanks to Matt and Mike for architecting your code in these really interesting ways! I hope you, like me, love seeing how other people do things–it can really improve the way you code so very quickly.

No comments: