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);
}
  • 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 '17 at 11:00
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
    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 '17 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
  • 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 '17 at 11:31
  • Did you call your handler class i.e MyClass inside trigger ? – Nachiket Deshpande Jun 1 '17 at 11:32
  • I haven't created the trigger yet. This error is on apex class. – Gaynerys Jun 1 '17 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. – Nachiket Deshpande Jun 1 '17 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 '17 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).

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.