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 {}
  • 1
    Boolean parameter is a bigger problem. Avoid Boolean Trap. – Adrian Larson Feb 18 '18 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 '18 at 15:36
  • Yes I prefer two methods. Some use Enum. – Adrian Larson Feb 18 '18 at 15:41
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.

| improve this answer | |
  • 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 '18 at 15:42
  • Makes sense! Queueable is a great solution if slightly-less-than-real-time is acceptable. – David Reed Feb 18 '18 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 '18 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 '18 at 16:49
  • 2
    Buy Dan Appleman's book. It's pretty much the best resource on async frameworks. – Adrian Larson Feb 18 '18 at 16:50

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.