4

I hope you'll help me to solve my problem :)

I've written a class that check if a Sobject has a field of a certain name

public static boolean hasSObjectField(String fieldName, SObject so){
    return so.getSobjectType().getDescribe().fields.getMap().keySet().contains(fieldName);
}

It works very fine, but there is one fault: it does not check system fields such as, for example, OwnerId.

Can you tell me what I've done wrong?

Regards!

1
  • Can you edit your post to include specific combinations you expect to exist that are failing?
    – Adrian Larson
    Sep 1, 2016 at 13:53

3 Answers 3

10

All the keys in the map are in lower case for some reason. I get a positive result for ownerid but not for OwnerId. I checked for our account object and all the keys in the map are lowercase.

This i think should fix it:

public static boolean hasSObjectField(String fieldName, SObject so){
            return so.getSobjectType().getDescribe().fields.getMap().keySet().contains(fieldName.toLowerCase());
}
8
  • 1
    The describe maps are case-insensitive.
    – Adrian Larson
    Sep 1, 2016 at 13:43
  • Probably should delete this particular answer since case-sensitivity is unlikely to be the cause.
    – Adrian Larson
    Sep 1, 2016 at 13:53
  • 1
    I'm still trying to understand this correctly. I tried this in the developer console and the solution seems to work. As the OP posts i can't find OwnerId for account but i can find ownerid. Do you think the OP has a different problem? (Of course i'll delete my answer as soon i understand)
    – Kasper
    Sep 1, 2016 at 13:56
  • 2
    @adrianlarson - ah -- but contains() is a case sensitive method; it is get on the map's key that is case insensitive, no?
    – cropredy
    Sep 1, 2016 at 15:23
  • 1
    Interesting. Using the m.containsKey() where m is a Map is case-insensitive, however once you grab m.keySet() you are back to case sensitive because you are operating on the string values of the Set and don't have access to the containsKey() method. And per the example above, the values of the set are all lcase.
    – Shanerk
    Feb 22 at 16:29
1

If you use dynamic SOQL and just wanna check results without try/catch or going thru metadata describe, you can use SObject.isSet() method.

0

Usually I'll just go ahead and write the code, assuming the field does exist, and catch the exception if it doesn't. e.g.

if(Trigger.isBefore && (Trigger.isInsert || Trigger.isUpdate))) {
    try {
        for(SObject o : Trigger.new) {
            Id ownerId = null;
            String s = String.valueOf(o.get('OwnerId'));
            if(s != null && s.startsWith('005')) {
                ownerId = (Id)s;
            }
            if(ownerId != (Id)o.get('Owner__c') ) {
                o.put('Owner__c',ownerId);
            }
        }
    }
    // if the field does not exist, an exception will be thrown
    catch(SObjectException ex) {
        System.debug(ex);
    } 
}

In most cases this is much faster, since presumably you are using fields that should exist and this is just to handle the niche scenarios.

If you really do need to check the field say because you are building up a field map for a custom query, then the previous answer works fine.

You must log in to answer this question.

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