Using a single trigger approach – how to manage the object changes – Before Insert mainly

I am trying to follow a single trigger approach.

  • there are several resources and patterns for it. I am doing something very simple

My main question: Whenever we need to add new functionality to the trigger (aka a new service class), how do I reference it? which data records am I passing to it?
I don’t want, nor think, that all logic needs to go in a single handler and/or class. So, if I seperate the logic to several ‘Service classes’ what’s the approach to reference the data set?
Can I always use either:

  • trigger.new
  • trigger.newmap

are they static to the trigger?

Do I need to return form a service class the list of ‘trigger.new’ that it received and may be modified?

Trigger:

trigger OpportunityTrigger on IJS__c (
before insert, after insert,
before update, after update, 
before delete, after delete)
{

    OpportunityHandler handler = new OpportunityHandler();

    if (Trigger.isBefore)
    {
        if (Trigger.isInsert)
        {
            handler.OpportunityService1(trigger.new);

            handler.OpportunityService2(trigger.new);
        }
        if (Trigger.isUpdate) { }
        if (Trigger.isDelete) { }
    }
    if (Trigger.IsAfter){
        if (Trigger.isInsert){ } 
        if (Trigger.isUpdate){ }
        if (Trigger.isDelete){  } 
    }
}

A Single Trigger Handler:

public without sharing class OpportunityHandler
{
    public void OpportunityService1 (List<Opportunity> objList)
    {
        // call Servicefunction1 and modify the data 

    }
    public void OpportunityService2 (List<Opportunity> objList)
    {
        // call ServiceFunction2 and modify the data 
    }
}

Several Service Classes

public without sharing class OpportunityService1 {

public OpportunityService1() {}

public void ServiceFunction1(){
    for(Opportunity opp :updatedOpportunitiesList)
    {
       opp.recordtypeid = system.label.SomeRecordTypeId;
    } 
}}

Second Service Class:

public without sharing class OpportunityService2 {

public OpportunityService2() {}

public void ServiceFunction1(){
    for(Opportunity opp :updatedOpportunitiesList)
    {
       opp.Name = 'set a new name';
    } 
}}
}

Answer

The usual pattern that I follow is a “factory” pattern with inheritance in action. In that case I would keep a parent class, which accepts the trigger.new or trigger.newMap values and then any service class will extend the parent class and thus has the values available during the lifecycle.

So think of something as below. This is just a sample, but I have used different versions of this different times. E.g., I would also pass the tigger.new or tigger.newMap as parameters to the base class sometimes. But overall, keeping a base class just simplifies the movement of the variables and follows a typical Object Oriented pattern here allowing inheritance and code re-usability.

public virtual class BaseClass {
    private List<SObject> newObjs; // expose using get/set methods
    private Map<Id, SObject> newIdMap; // expose using get/set methods
    ....
    public BaseClass() {
        newObjs = Trigger.new;
        newIdMap = Trigger.newMap;
    }
    ... all my other stuff ...
 }

Then you have child services extending this class as:

public class Service1 extends BaseClass {
    public Service1() {
       super();
    }
    ... these classes will always have the reference of the new/newMap ...
 }

And then you initialize the BaseClass from your trigger.

trigger AccountTrigger on Account (before insert ...) {
    Service1 s1 = new Service1();
    Service2 s2 = new Service2();
    ... all other stuff ...
}

As for your questions:

are they static to the trigger?

The answer is no, as you can see above. Trigger context variables can be used in Apex classes within the transaction context. It’s just that you should be aware of what are you expecting in those list/maps.

Whenever we need to add new functionality to the trigger (aka a new service class), how do I reference it? which data records am I passing to it? I don’t want, nor think, that all logic needs to go in a single handler and/or class. So, if I seperate the logic to several ‘Service classes’ what’s the approach to reference the data set?

The above approach lets you to just create a new service class and extend the base class and refer the variables as soon as your class is initialized, as you are assigning the variables within the constructors.

Do I need to return form a service class the list of ‘trigger.new’ that it received and may be modified?

No, because its being referenced in the service classes within the same transaction context.

Hope this helps.

Attribution
Source : Link , Question Author : Saariko , Answer Author : Jayant Das

Leave a Comment