function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
EUSEUS 

trigger.oldMap can be an argument to a class method?

Hi,

 

I have a trigger after insert and after update for an sObject which I would like to process with a Class Method and not at the trigger itself.  So I am passing the trigger.new list to the method and I also need to compare the previous fields on the oldMap structure to confirm whether or not the fields have been updated.  Can I pass the trigger.oldMap Map to the method? Also the method is a webservice method.

 

I tried to pass the map with no luck! ... Also just tried to use the oldMap in the webservice, assuming the Map would be available and it does not work! However the same statement used in the trigger snippet works.... Only I'd rather process all code at the class instead of the trigger.

 

Any ideas or suggestions?

 

Here is the trigger code that works:

 

for (Member__c Mbr : Trigger.new) {
      Member__c oldMember = Trigger.oldMap.get(Mbr.ID);
       if (Mbr.Merchant__c != oldMember.Merchant__c) {  // Merchant Id has changed so I need to process it.
               // more code here...
       }

rList =  Member.memberUpdate(trigger.new);                 // Here I call the webservice method and pass the trigger.new List

 

The same code would not work at the webservice method (I think it losses context of trigger.oldMap there)...

 

Here is the websercie code:

 

 webservice static void memberUpdate(list<Member__c> nMb) {
     
      for (Member__c MBR : nMb) {
       Member__c oldMember  = Trigger.oldMap.get(MBR.ID);
       //

 

The error I get from force.IDE is the following:

Save error: Illegal assignment from SObject to SOBJECT:Member__c

 

Thanks!

 

Peter_sfdcPeter_sfdc

You'll need to change the method signature of your method you're calling. You can't expect the Trigger context variables to be there when you invoke a method, you must pass them is as params. Like this: 

 

Trigger Code: 
for (Member__c Mbr : Trigger.new) {
      Member__c oldMember = Trigger.oldMap.get(Mbr.ID);
       if (Mbr.Merchant__c != oldMember.Merchant__c) {  
               // more code here...
       }
rList =  Member.memberUpdate(trigger.new,Trigger.oldMap);  <-- pass the old map
 
Method Code:  
 webservice static void memberUpdate(list<Member__c> nMb,Map<Id,Member__c> oMb) {
     
      for (Member__c MBR : nMb) {
       Member__c oldMember  = oMb.get(MBR.ID);
       //

 My question for you is why are you attempting to use this web service code for the purposes of trigger processing? If you were to write that code, you could end up breaking it, as Trigger.oldMap will never be in the context of your webservice calls. 

 

I applaud you for trying to reuse code, but you might have to do a little refactoring so that you maintain the integrity of your web service method, but still reuse the common logic between what you want to do with your trigger and what the webservice is supposed to do. 

 

Happy coding.

sfdcfoxsfdcfox

Each class has to be compiled into bytecode, which is fully self-contained Apex Code in compiled form. Outside the context of a trigger, Trigger.newMap and Trigger.oldMap would probably lose their identity (meaning that they could only be interpreted as a generic SObject list). Following this logic, you should be able to cast from a generic to a specific using the following line of code:

 

Member__c oldMember = (Member__c)Trigger.oldMap.get(mbr.id);

However, I'd say it's probably worth rewriting the web service to simply accept up to two lists of objects, and generating maps from there:

 

webservice static void memberUpdate(Member__c[] oldList, Member__c[] newList) {
    Map<Id,Member__c> oldMap = new Map<Id,Member__c>(oldList!=null?oldList:newList),
                      newMap = new Map<Id,Member__c>(newList);
    // more code follows.
}

And, appropriately, change your invocation:

 

Member.memberUpdate(trigger.old, trigger.new);

The ternary operator in the second block of code allows us to consider newList to be oldList in the event that this is being called from an insert trigger. If this isn't a concern, don't use that logic. In the event that you'd like to use that web service call as a web service, you'll probably want two different versions:

 

webservice static void memberUpdate1(Member__c[] newList) {
    memberUpdate2(newList, newList);
}

webservice static void memberUpdate2(Member__c[] oldList, Member__c[] newList) {
    // Your code here.
}

I recommend calling them "1" and "2" only because I'm not sure how well SOAP handles "overloaded" functions that differ only by their parameter signature.

EUSEUS

Hi Peter,

 

Thanks for your answer. I tried to use the Map with the webservice but force.IDE says it's Illegal use of Map .... as I tested it before....  I guess webservice methods do not accept trigger Maps as arguments...

 

I was thinking about your comment, and definitively I'll never be able to reuse the webservice with a trigger Map as an argument, even if I get to make it work, ...so the code won't be reusable anyways!. 

So, I will change the webservice to global and I think it will work, only for the triggers though!

 

Thanks a lot for your help.

 

Cheers!