1

I'm trying to create a generic utility method which takes a List of sObjects and a Map of fieldNames to fieldValues. I'd like to, for example, do the following:

List<Lead> leadList = [SELECT Id FROM Lead WHERE...];

Map<String,Object> fieldValueMap = new Map<String,Object>();
fieldValueMap.put('MailingCountry','United States');
fieldValueMap.put('Description','My New Description');

update UtilityClass.updaterMethod(leadList, fieldValueMap);

Here's what I've got so far. My challenge is that I don't want to have loops within loops (that's gotten me into CPU time limit issues before).

Challenge: Given that the Map is of indeterminate size, how would I dynamically set any number of field values within the sObject loop without an inner loop?

public static List<SObject> setFieldValue(List<SObject> sobjList, Map<String,Object> fieldNameValueMap, Boolean skipInvalid) {

    List<SObject> updatedList = new List<SObject>();

    for(SObject sobj : sobjList) {

        try {
            //Written as if I had a single fieldName/Value parameter...
            sobj.put(fieldName, fieldValue); //This is what needs to be replaced
            updatedList.add(sobj);
        }
        catch(Exception e) {
            if(skipInvalid) {}
            else {
                String typeString = sobj.getSObjectType().getDescribe().name;

                //Written as if I had a single fieldName/Value parameter...
                throw new TypeException(typeString + ' does not have a field called ' + fieldName, e);
            }
        }
    }

    return updatedList;
}

public class TypeException extends Exception {}
3
  • 1
    Boolean parameter is a bigger problem. Avoid Boolean Trap.
    – Adrian Larson
    Feb 18, 2018 at 5:06
  • @AdrianLarson thanks for the heads up, I'm new to this and didn't know about that. What's the suggested alternative? Two methods, one for each boolean value?
    – Mike
    Feb 18, 2018 at 15:36
  • Yes I prefer two methods. Some use Enum.
    – Adrian Larson
    Feb 18, 2018 at 15:41

1 Answer 1

4

Loops within loops aren't bad per se. They're bad when they either (a) are an inefficient way of expressing functionality or (b) represent an attempt to execute some code whose computational complexity is just too high to take place in a 10 second Salesforce transaction.

In this case, I think you will probably be fine with an inner loop, which is the natural way to express this functionality. If you run into CPU limit issues, I would recommend looking at other code first as the culprit - the analysis views in the developer console can help clarify where the time consumption issue lies.

6
  • Thanks @David, I've gone ahead and written it with an inner loop. To mitigate any CPU time limit issues, for my current need, I put the whole thing in a queueable... It was initially intended to be a synchronous, before insert/update action, but it's not crucial to occur at insert/update.
    – Mike
    Feb 18, 2018 at 15:42
  • Makes sense! Queueable is a great solution if slightly-less-than-real-time is acceptable.
    – David Reed
    Feb 18, 2018 at 16:02
  • @Mike just be careful you don't try to enqueue two jobs from a job. Don't assume you can enqueue. Add logic to check if it's viable and fall back gracefully. That way if you ever batch over this object and you have more than one Queueable operation you can just perform them synchronously.
    – Adrian Larson
    Feb 18, 2018 at 16:45
  • @AdrianLarson Thanks - I'm actually pretty new to using Queueable. I've read through the docs, but I don't have the experiential knowledge of pitfalls. Do you possibly have a link to a thread either here or elsewhere expanding on the potential issue you've outlined?
    – Mike
    Feb 18, 2018 at 16:49
  • 2
    Buy Dan Appleman's book. It's pretty much the best resource on async frameworks.
    – Adrian Larson
    Feb 18, 2018 at 16:50

You must log in to answer this question.

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