3

Every time one of my records which has a Trigger is changed, I'll need to check whether the record's RecordTypeId is listed in a Custom Setting, before calling any other methods from the Trigger.

trigger WE_MasterOppTrigger on Opportunity (
    before Insert, after Insert,
    before Update, after Update,
    before Delete, after Delete){

        RecordTypeChecker checker =
            new RecordTypeChecker(Trigger.newMap);
        checker.validateRecordTypes();

        //retrieve validated Opps & process with below classes

        if(validatedOpps.size() > 0{

            if(Trigger.isBefore){
                if(Trigger.isInsert){
                    //class logic
                }
             }
             //etc
          }

So I've created a Class to manage the record type checks & ideally that Class would be able to receive inputs from Triggers with the same structure, for different objects.

public RecordTypeChecker(
    Map<Id,Opportunity> newTriggerOpps,
    Map<Id,MPM4_BASE__Milestone1_Project__c> newTriggerProjs
   ){
        newOpps = newTriggerOpps;
        newProjs = newTriggerProjs;
    }

But when I try to create the above constructor which can receive inputs either from Opportunity's Trigger.newMaps or Project's and call the Method from my Opportunity trigger, it causes the error

Constructor not defined: [RecordTypeChecker].(Map<Id,Opportunity>)

When I comment out the Projects sections of the constructor, there are no errors -

public RecordTypeChecker(
    Map<Id,Opportunity> newTriggerOpps
   //Map<Id,MPM4_BASE__Milestone1_Project__c> newTriggerProjs
   ){
        newOpps = newTriggerOpps;
        //newProjs = newTriggerProjs;
    }

So I guess that the map for the Projects which is not receiving an input is causing the issue.

Will I have to create one of these Classes per object (& Before / After map)?

3

A class with this signature can be called from triggers of any type:

public class RecordTypes {

    public static void validate(SObject[] oldSobs, SObject[] newSobs) {
        if (oldSobs != null) validate(oldSobs);
        if (newSobs != null) validate(newSobs);
    }

    private static void validate(SObject[] sobs) {
        SObjectType t = sobs[0].getSObjectType();
        for (SObject sob : sobs) {
            Id rtId = (Id) sob.get('RecordTypeId');
            if (t == Opportunity.SObjectType) {
                // ...
            } else if (t == Project.SObjectType) {
                // ...
            }
        }
    }
}

e.g.:

trigger WE_MasterOppTrigger on Opportunity (
        before Insert, after Insert,
        before Update, after Update,
        before Delete, after Delete
        ) {
    RecordTypes.validate(Trigger.old, Trigger.new);
    ...
}

because SObject is the base type of all standard and custom objects and has methods to access the fields in a generic way.

The two list Trigger context values have to be passed in to deal with all the execution contexts of before/after insert/update/delete.

  • Thanks Keith so I can see how to manage the trigger contexts now, using your solution. Am I right in thinking that I can use the Describe schema method to also check whether the object is an Opportunity or Project - which will then determine which field to check in the Custom Setting for the matching RecordTypeIds? (This is the reason for trying to use the two separate maps in my controller). – Alex S Jul 11 '15 at 18:07
  • 1
    @AlexS I've added a bit more to the answer related to varying the logic based on type. (You only need to make a describe call if you want detail of the structure of the object.) With just an SObjectType t you can get the type name using String.valueOf(t) and use that to e.g. lookup a custom setting. – Keith C Jul 11 '15 at 18:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.