2

As best practice, I am trying to put logic in my trigger into an apex class. But there's this error saying

Variable does not exist: oldMap

The apex trigger works now as expected, but not sure how to do it right in apex class.

Meanwhile, here's the Apex Trigger:

trigger MyTrigger on Object__c (before update) {

    for(Object__c o : Trigger.new) {

        if(o.Lookup_Field__c != Trigger.oldMap.get(o.Id).Lookup_Field__c && o.Original_Lookup_Value__c == null) {

            o.Original_Lookup_Value__c = Trigger.oldMap.get(o.Id).Lookup_Field__c;

        }

    }

}

And here's what I've tried so far...

Apex Class:

public class MyClass {

    public void OriginalValue() {

        List<Object__c> oList = new List<Object__c>(); 

        oList = [SELECT Id, Name, Lookup_Field__c, Lookup_Field__r.Name, Original_Lookup_Value__c FROM Object__c];

        if(!oList.isEmpty()) {

            if(oList[0].Lookup_Field__c != oList[0].oldMap.get(oList[0].Id).Lookup_Field__c) {

                oList[0].Original_Lookup_Value__c = oList[0].oldMap.get(oList[0].Id).Lookup_Field__r.Name;

            }

        } 

    }

}

Updated Apex Class

public class MyClass {

    public void OriginalValue(List<Object__c> newList, Map<String,Object__c> oldMapObject) {

        if(!newList.isEmpty()) {

            for(Object__c o : newList) {

                if(o.Lookup_Field__c != oldMapObject.get(o.Id).Lookup_Field__c && o.Original_Lookup_Value__c == null) {
                    o.Original_Lookup_Value__c = oldMapObject.get(o.Id).Lookup_Field__r.Name;       
                }

            }
        } 
    }
}

Updated Apex Trigger:

trigger MyTrigger on Object__c (before update) {
    MyClass myObj = new MyClass();
    myObj.OriginalValue(Trigger.new,Trigger.oldMap);
}
1
  • if you need to use oldMap and NewMap in your class, you need to call the class's method from trigger and then pass trigger.new to that method.Then you can iterate over it and find the old value and new value.
    – Samir
    Jun 1, 2017 at 11:00

4 Answers 4

3

To do that you first need to send Trigger.new and Trigger.oldMap to your helper method as follows:

Trigger

trigger MyTrigger on Object__c (before update) {
    MyClass myObj = new MyClass();
    myObj.OriginalValue(Trigger.new,Trigger.oldMap);
}

Trigger handler

public class MyClass {

    public void OriginalValue(List<Object__c> newList, Map<String,Object__c> oldMapObject) {

        if(!newList.isEmpty()) {
            // code goes here
        } 
    }
}
1
  • 1
    Your statement on the availability of Trigger Context Variables (TCVs) outside of triggers isn't quite right. Trigger.isExecuting is always populated with either true or false. If Trigger.isExecuting is true, then other TCVs will be populated (otherwise, I believe all other TCVs will be null). In this case, because the OriginalValue() method of MyClass is being called from a trigger context, the TCVs will be populated, and can be used. That said, using TCVs outside of the trigger body to avoid specifying/passing parameters is bad practice, and would make such a class harder to test
    – Derek F
    Jun 1, 2017 at 13:03
1

There are two methods to do it

Method 1:

1. Pass Trigger.new and Trigger.oldMap as a parameter to Trigger Handler
//Your Trigger 
trigger MyTrigger on Object__c (before update) {
  new TriggerHandler().OriginalValue(Trigger.new,Trigger.oldMap);
}

//TriggerHandler
public class TriggerHandler {

    public void OriginalValue(List<Object__c> newObjectList, Map<ID,Object__c> oldSobjectMap) {

        //Your Logic
    }
}


Method 2:
Advantages of Method 2:
1. You don't have to worry about passing parameter from your trigger.
2. If in future you got need to pass any additional parameter, you can pass that in handler using context variables and only your service class will be affected which is providing service to your trigger.
3. This will also make your Trigger design simpler and flexible considering future modifications.

//Using Context Variable
//Your Trigger calling handler method
trigger MyTrigger on Object__c (before update) {
  new myTriigerHandler().onBeforeUpdate();
}

//Trigger Handler
public class myTriigerHandler {

    //Here you can call methods for each events of trigger and then can 
      //provide the service.
    public void onBeforeUpdate() {
      //You can use trigger context to pass parameter to
        new myTriigerSerice().OriginalValue((List<Sobject>) Trigger.new,(Map<Id,Sobject>) Trigger.oldMap)
    }
}

//Service Class
public class myTriigerSerice {
  public void OriginalValue(List<Object__c> newObjectList, Map<Id,Object__c> oldSobjectMap) {

        //Your Logic
    }
}service class
7
  • I added a modified version of the apex class below my post. Right now, I am encountering this error: Variable does not exist: Lookup_Field__c.
    – Gaynerys
    Jun 1, 2017 at 11:31
  • Did you call your handler class i.e MyClass inside trigger ? Jun 1, 2017 at 11:32
  • I haven't created the trigger yet. This error is on apex class.
    – Gaynerys
    Jun 1, 2017 at 11:34
  • Why you are using newList[0] , using zeroth element in list , you need to write trigger to support bulk data, use for loop like for(Object__c objObject : newList){ objObject.Lookup_Field__c = some value } Also you need to provide value to newList, how would apex know newList has value for Lookup_Field__c ? earlier you were perfroming SOQL query, trigger.new will provide value to newList. Jun 1, 2017 at 11:46
  • Error on apex class is gone, and I already called it on the apex trigger. However, there's this error on the trigger: Method does not exist or incorrect signature: void OriginalValue(List<Object__c>, Map<Id,Object__c>) from the type MyClass. Can you check my post? I already added both updated apex class and trigger on it.
    – Gaynerys
    Jun 1, 2017 at 11:59
0

You should call your class from trigger code, and pass the Trigger.oldMap, Trigger.new to the class methods, then you can use those maps and list directly in class.

You have tried to use oList[0].oldMap, which is not correct, oldMap is a context variable and should be used with keyword Trigger.

Here are a couple of helpful links, you can follow. https://developer.salesforce.com/page/Trigger_Frameworks_and_Apex_Trigger_Best_Practices https://www.tutorialspoint.com/apex/apex_trigger_design_pattern.htm

0

I recommend you to use an existing framework instead of trying to build your own logic for this. Take a look at Kevin O'Hara's Trigger Framework. It is simple to use, and comes with handy functionality (bypasses in case of loops, trigger count, etc).

Using this framework allows you to call the Trigger context variables normally, and your code is entirely on a class. The trigger will have just one line (to call the class that will handle the trigger context).

You must log in to answer this question.

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