From a general stand point, salesforce.com advises against querying more fields than you need due to performance issues, not to mention that there is an upper limit on the maximum size of a query.
That aside, sometimes you do need all fields, because you're exporting, migrating, deduplicating, or many other reasons. Usually, though, it would be better to split the functionality into two calls (for performance reasons): (1) select id from sourceobject where ...
, then (2) retrieve(sourceobject, queryresultids, fields)
.
Regardless, using one API call or two, you still need to know which fields are which. This is where isAccessible
comes into play. When you describe an object, each field that the user can currently access will have isAccessible
set to true. When false, the user can't query against that field.
ShippingLatitude, by the way, isn't a phantom field; it is a sub-field of the UI element "shipping address", which has seven fields (street, city, state, postal code, country, latitude, and longitude). The UI is prone to showing some fields as a single field set, in particular address fields. You can't see it in the UI/setup screen, but that doesn't mean it doesn't exist. Assuming the user has "read" access to "Shipping Address", they will have access to the seven fields mentioned previously.
If your query is failing, check the field level security for the address field in the UI. Most likely, you'll find that the "field" is hidden, disabling all of those fields. Even system administrators can't violate field level visibility, so be sure that it is set appropriately. Administrators can describe all fields, however, which is why it is misleading to assume that just because a describe shows a field as available means the administrator has permission to query it.
You can do it like this:
Map<String, String> labelMap = new Map<String, String>();
Schema.DescribeSObjectResult objectDescribe = My_Object__c.SObjectType.getDescribe();
Map<String, Schema.SObjectField> fieldMap = objectDescribe.fields.getMap();
for( String fieldName : fieldMap.keySet() ) {
Schema.SObjectField field = fieldMap.get( fieldName );
Schema.DescribeFieldResult fieldDescribe = field.getDescribe();
labelMap.put(fieldDescribe.getLabel(), fieldDescribe.getName() );
}
Best Answer
Elegant? Perhaps not, but checking
'Name'
first and only iterating as a fallback plan should be more efficient. With every custom object and most standard objects, this shortcut will cut out the looping and additional describes entirely.My natural inclination is to start with a positive condition:
It may be more elegant, however, to use a negative condition and DRY on the
return 'Name'
front.