AnotherBoringUtilClass: Extract a Set from a List
by Simon Goodyear.
Average Reading Time: about a minute.
Yet another update to the AnotherBoringUtilClass.
This time it’s to extract a Set of fields from a list of objects. I find myself writing the same loop over and over to do this work – often in a trigger or another bulkification scenario. The idea is that this method will take a list of objects and return you a set of the values associated with one particular field in that object. So for example; here’s a list of contacts, return me a set of all of the AccountIds they’re related to. This set can then be used to query the accounts in one nice quick SOQL statement; yes I know I’m teaching you all things you already know – send me your Grandmother’s address if you’re offended.
public static Set<Object> extractFieldValues(List<sObject> input, String fieldName){
Set<Object> output = new Set<Object>();
for(sObject obj : input){
output.add(obj.get(fieldName))<wbr>;</wbr>
}
return output;
}
And you could use it in a trigger like so:
trigger DoSomethingSilly on Contact (after insert){
Set<Id> accountIds = AnotherBoringUtilClass.<wbr>extractFieldValues(Trigger.<wbr>new, 'AccountId');</wbr></wbr>
List<Account> accs = [SELECT Id, NumberOfEmployees FROM Account WHERE Id IN :accountIds];
for(Account acc : accs){
acc.NumberOfEmployees += 1;
}
update accs;
}

Very nice idea. A utility method like this usually comes in handy to prepare SOQL queries with IN.
A few hints from my side, if you plan to include this utility into a general solution, e.g. a managed package.
1) If you accept a String for the fieldname, you might end up with exceptions due to typos, changed fieldnames or package namespaces. If you accept a field token instead of the fieldname, you avoid all these issues as SF takes care of all these things.
Of course typos will usually popup immediately during development, but renaming of fields or problems that popup in the managed package only will be pretty hard to find (if you’re not used to these kind of issues).
2) For most IN queries I would like to skip null values or empty strings in the Set as otherwise you will get lots of results what don’t make sense at all. This will usually not be an issue with IDs but with all other fields, e.g. external IDs.
Taking that into consideration, the method would then have a couple of more lines:
public static Set extractFieldValues(List input, Schema.SObjectField fieldToken, Boolean skipEmptyValues){
if (fieldToken == null || input == null || input.isEmpty()) return new Set();
String fieldName = fieldToken.getDescribe().getName();
Set output = new Set();
for(sObject obj : input){
try {
Object value = obj.get(fieldName);
//the following lines can be merged into a single but hard to understand IF, so for readability I prefer it this way:
if (!skipEmptyValues) {
output.add(value);
} else {
if (value != null) {
if (value instanceof String) {
if ( ((String) value).trim() != ”) output.add(value);
} else {
output.add(value);
}
}
}
} catch (Exception e) {
//happens if sObject does not have a reference to this field => handle it or drop it…
}
}
return output;
}
A call would look like this:
Set accountIds = AnotherBoringUtilClass.extractFieldValues(Trigger.new, Contact.AccountId, true);
hth
Ingo
Ingo -
Some great updates, thanks. I should have thought about the field token, it’s a much more robust solution; I often overlook the metadata when it can be so powerful.
Cheers