I've got a class with an @future
annotated method that gets called in an after
Trigger context variable (it's an asynchronous callout, so it needs to be in Trigger.after
) and performs Database.update(objectList, false)
DML.
Currently it takes in some parameters, plus Set<Id>
which gets passed in via Trigger.newMap.keySet()
. I can query for the records in the method itself, process them and update them.
This works well for records passed in via Trigger.insert
context, but if I try this in Trigger.update
, I'm going to run into recursion problems. To do this I'm going to have to compare fields and if they're different, update them. Otherwise don't.
Now if I pass in Trigger.newMap().keySet()
and Trigger.oldMap.keySet()
and query for them, I'm going to get the same records. As per the docs, I can't pass in a List<sObject>
nor a Map<Id, sObject>
so I'm stuck in a position where I need to compare old and new sObjects, but can only pass in the Id
.
Below is some code that roughly represents what I'm looking to do:
if (Trigger.isAfter) {
if (Trigger.isInsert) {
MyClass.MyMethod(Trigger.newMap.keySet()); // Works fine. Can query for the records
}
if (Trigger.isUpdate) {
MyClass.MyMethod(Trigger.new, Trigger.old); // Won't work. Salesforce doesn't allow sObjects passed in to @future methods
MyClass.MyMethod(Trigger.newMap, Trigger.oldMap); // Won't work. Salesforce doesn't allow Maps passed into @future methods
MyClass.MyMethod(Trigger.newMap.keySet(), Trigger.oldMap.keySet()); // Won't work. Querying for the Ids will return the same values as it's in the after context
}
}
public class MyClass {
@future
public static void MyMethod(Set<Id> mySet) {
List<sObject> objList = Database.query('SELECT [...] FROM [...] WHERE Id IN :mySet');
// Change field values
Database.update(objList, false);
}
@future
public static void MyMethod(Map<Id, sObject> newMap, Map<Id, sObject> oldMap) {
List<sObject> objList = new List<sObject>();
for (sObject obj : newMap.values()) {
sObject oldObj = oldMap.get(obj.Id);
if (obj.Field__c != oldObj.Field__c) {
objList.add(obj);
}
}
if (objList.size() > 0) {
// Update stuff...
Database.update(objList, false);
}
}
}
Now I know that I could just simply do something similar to the second method above and compare the values and call the method in the Trigger itself but the idea behind what I'm writing is to make the class itself do the legwork and keep Trigger code minimal.
So I'm wondering if anyone has get any luck in doing something creative and similar to what I'm after, or I'll have to resign myself to doing the comparison logic in the Trigger.
Is it possible to compare Trigger.new/newMap with Trigger.old/oldMap in an @future
method?
If(!System.isFuture())
which will always return false if the trigger is getting called because of the updation done in future method@future
method is really what I'm trying to do.