33

So I was kind of throwing round the idea of making a generic apex trigger that is callable by multiple objects. Say you have the following sObjects:

Account
Sales__c
Sales_Contacts__c

And I wanted to make a trigger that is called when any of those objects are updated - for example:

trigger autoTaskCreation on Account, Sales__c, Contacts (after insert, after update) {
    for (sObject s :Trigger.new) {
        AutoTaskCreation a = new AutoTaskCreation();
        a.createTask(s);
    }
}

and then on the controller side:

public with sharing class AutoTaskCreation {

    private integer _returnvalue;
    private string _objecttype;

    public void createTask(sObject s)
    {
        _objecttype = s.getSObjectType();
        if (_objecttype == Account )
        {
            _returnvalue = _createcccounttask();
        }
        else if(_objecttype == Sales__c)
        {
            _returnvalue = _createsalestask();
        }
        else
        {
            _returnvalue = _createsalessontacttask();
        }
    }
}

Has anyone done something similar to this/does apex reflection support generics in this way? Any help would be appreciated!

1

1 Answer 1

36
+50

You've got the general idea from your answer. Dynamic Apex and Dynamic SOQL are the best way to reflect on SObject's and as you've discovered you can determine the type easily. I would ensure however your method takes a list of SObject so it can implement bulkfication.

public void createTask(List<SObject> records)

You can use the List method getSObjectType to get the type of objects in the list. You will also need multiple triggers, but you can simplify each of them into a single line, like so.

trigger autoTaskCreation on Account (after insert, after update) {
    new AutoTaskCreation().createTasks(Trigger.new);
}

However you will not then know the event being handled from within the createTasks method. You can either pass this as an additional parameter or to make your Trigger even simpler and your method handle future events without modifying the signature. You could do something like this...

trigger autoTaskCreation on Account (after insert, after update) {
    AutoTaskCreation.handleTrigger();
}

Then define your AutoTaskCreation class something like this....

public class AutoTaskCreation
{
    private List<SObject> Records;

    public AutoTaskCreation(List<SObject> records)
    {
         this.Records = records;
    }

    public void onHandleAfterInsert()
    {
         SObjectType objectType = Records.getSObjectType();
    }

    public void onHandleBeforeInsert()
    {
         SObjectType objectType = Records.getSObjectType();
    }

    public static void handleTrigger()
    {
         // Create handler and delegate events to methods
         AutoTaskCreation taskCreation = new AutoTaskCreation(Trigger.new);
         if(Trigger.isBefore && Trigger.isInsert)
             taskCreation.onHandleBeforeInsert();
         else if(Trigger.isAfter && Trigger.isInsert)
             taskCreation.onHandleAfterInsert();
    }
}

More Advanced: If you wanted to get more sophisticated, instead of the if/else approach in the handlers, you could develop this idea out as an Apex base class. Extending from other classes and overriding base class methods to specialise for the specific objects you want to support. Implementing a factory pattern to register the derived classes for the triggerHandler method to instantiate via Type.newInstance automatically based on the object type.

Further Info: This is simpler example on a number of broader Trigger patterns I've seen, including one of my own. If you want to take a broader look at them, I've listed the ones I'm aware below, others may have their preferences. Most I've seen should allow you to map a single trigger handler class to an object, but none will workaround the need for a distinct trigger per object, the best we can do is minimise the logic in each trigger. Note that these do vary on features and overhead.

6
  • 5
    On the subject of trigger patterns, they may bring benefits to your own app but they are not a silver bullet. The Force.com platform by design allows multiple apps to be installed, and each will typically add triggers to objects like Contact, Account, Task, Attachment, Note with no cross-app orchestration possible. So for the shared objects particularly, ensure your triggers only do work (SOQL calls or particularly updates that typically cause further triggers to run) where necessary i.e. check for the specific field changes that your triggers need to handle and ignore all other changes.
    – Keith C
    Oct 1, 2013 at 17:22
  • This was an awesome answer, thank you so much for the links to external resources as well!
    – gfppaste
    Oct 1, 2013 at 19:20
  • @KeithC yes good point, regardless of the use of such patterns, this is a good practice. It has got me wondering if such handlers can introspect this for the developer and only delegate to handler methods if specific fields (or those from the packaged namespace) have changed, hmmm.... :) Oct 1, 2013 at 21:00
  • I think this is more than a good practice: one app with lazily coded triggers can break the other apps and source code in an org. So building clean change detection in a trigger framework gets a +1 from me...
    – Keith C
    Oct 1, 2013 at 21:37
  • What a high quality answer this is! +50
    – JannieT
    Nov 28, 2013 at 12:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .