How to know if a field is part of a compound address field and thus is not permissionable

I am working on a class that dynamically created FieldPermissions records for a permission set. This is working fine, except when it comes to standard compound address fields. When you attempt to create a FieldPermissions record for Contact.MailingStreet using the following code

PermissionSet perm = new PermissionSet(Name='Test_Perm_Set',Label='test Perm Set');
insert perm;
insert new FieldPermissions(SobjectType='Contact',PermissionsRead=true, Field='Contact.MailingStreet', ParentId=Perm.Id);

it errors out. Inexplicably, the error reads

FATAL_ERROR System.DmlException: Insert failed. First exception on row 0; first error: INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST, Field Name: bad value for restricted picklist field: Contact.MailingCity: [Field]

Clearly not expected behavior, right there!

Even weirder, the FieldPermissions docs identify that a field will describe itself as not permissionable in it’s describe result if you cannot create a FieldPermissions for it. And yet…

System.debug(Contact.SObjectType.getDescribe().Fields.getMap().get('MailingStreet').getDescribe().isPermissionable());

Returns true.

Is this a platform bug that these fields are responding as permissionable? Is there some combination of describe flags that would let me know that they aren’t permissionable?

EDIT: To answer a question from twitter, yes, there is no error when creating a permission for the Contact.MailingAddress field. However, fieldsets contain the component fields instead of the compound field, so I’m looking for some logic other than hardcoded replaces to know to deal with the compound field (or at least not error on the components).

Answer

There is an easy way to determine if field is a real field or a part of compound field.

There are two tables in Salesforce which correspond to compound fields and its components.

If a field can be found in FieldDefinition table, it is a real (permissionable) field. If a field cannot be found in FieldDefinition table, but can be found in EntityParticle table, it is a part of compound field and not a separate independent field.

So, you can easily detect if field is part of compound field by making a query.

SELECT BusinessOwnerId,BusinessStatus,ControllingFieldDefinitionId,DataType,Description,DeveloperName,DurableId,EntityDefinitionId,ExtraTypeInfo,Id,IsApiFilterable,IsApiGroupable,IsApiSortable,IsCalculated,IsCompactLayoutable,IsCompound,IsFieldHistoryTracked,IsHighScaleNumber,IsHtmlFormatted,IsIndexed,IsListFilterable,IsListSortable,IsListVisible,IsNameField,IsNillable,IsPolymorphicForeignKey,IsSearchPrefilterable,IsWorkflowFilterable,Label,LastModifiedById,LastModifiedDate,Length,MasterLabel,NamespacePrefix,Precision,PublisherId,QualifiedApiName,ReferenceTargetField,ReferenceTo,RelationshipName,RunningUserFieldAccessId,Scale,SecurityClassification,ServiceDataTypeId,ValueTypeId FROM FieldDefinition where DurableId = 'Contact.MailingStreet'

or, simply put,

SELECT DeveloperName,DurableId,EntityDefinitionId FROM FieldDefinition where DurableId = 'Contact.MailingStreet'

Since this query returns zero results,

enter image description here

this means that there is no definition of field with name MailingStreet on Contact.

To be sure that there is no such field if you would try to adopt this logic for custom fields, you can change the filter criteria to include QualifiedApiName

SELECT DurableId FROM FieldDefinition where EntityDefinitionId = 'Contact' AND QualifiedApiName = 'MailingStreet'

enter image description here

While for real field like Mailing Address, the similar query would return result

enter image description here

To find all field parts of compound fields, query EntityParticle table.

SELECT ByteLength,DataType,DefaultValueFormula,DeveloperName,Digits,DurableId,EntityDefinitionId,ExtraTypeInfo,FieldDefinitionId,Id,InlineHelpText,IsApiFilterable,IsApiGroupable,IsApiSortable,IsAutonumber,IsCalculated,IsCaseSensitive,IsCompactLayoutable,IsComponent,IsCompound,IsCreatable,IsDefaultedOnCreate,IsDependentPicklist,IsDeprecatedAndHidden,IsDisplayLocationInDecimal,IsEncrypted,IsFieldHistoryTracked,IsHighScaleNumber,IsHtmlFormatted,IsIdLookup,IsLayoutable,IsListVisible,IsNameField,IsNamePointing,IsNillable,IsPermissionable,IsUnique,IsUpdatable,IsWorkflowFilterable,IsWriteRequiresMasterRead,Label,Length,Mask,MaskType,MasterLabel,Name,NamespacePrefix,Precision,QualifiedApiName,ReferenceTargetField,ReferenceTo,RelationshipName,RelationshipOrder,Scale,ServiceDataTypeId,ValueTypeId FROM EntityParticle where EntityDefinitionId = 'Contact' and IsCompound = false AND FieldDefinitionId IN (
SELECT DurableId FROM 
FieldDefinition
where IsCompound = true)

Since you can find MailingStreet record in these results, you can confirm that it is truly part of compound field.
enter image description here

I think even better to check `IsComponent’ property alone.

SELECT DataType,DeveloperName,DurableId,EntityDefinitionId,FieldDefinitionId,IsComponent,IsCompound,Label,Name,QualifiedApiName
FROM EntityParticle
where EntityDefinitionId = 'Contact' and IsComponent = true

So this query is simpler and returns the same 23 results.

enter image description here

Even it is possible to execute query to return this record without knowing its DurableId filtering by QualifiedApiName, Name or Label like this:

SELECT DataType,DeveloperName,DurableId,EntityDefinitionId,FieldDefinitionId,IsComponent,IsCompound,Label,Name,QualifiedApiName
FROM EntityParticle
where EntityDefinitionId = 'Contact' AND QualifiedApiName = 'MailingStreet'

enter image description here

Also, another way to find out if field is a component of a compound field without making SOQL queries is to check getCompoundFieldName() method on fieldDescribe result. It returns a name of Compound Field for a component of a compound field and returns null in other cases.

System.debug(LoggingLevel.ERROR, '@@@ v: ' + Test__c.Geolocation__Latitude__s.getDescribe().getCompoundFieldName() );
System.debug(LoggingLevel.ERROR, '@@@ v: ' + Test__c.Geolocation__c.getDescribe().getCompoundFieldName() );
System.debug(LoggingLevel.ERROR, '@@@ v: ' + Contact.MailingStreet.getDescribe().getCompoundFieldName() );
System.debug(LoggingLevel.ERROR, '@@@ v: ' + Contact.MailingAddress.getDescribe().getCompoundFieldName() );

enter image description here

So instead of checking Contact.MailingStreet.getDescribe().isPermissionable() you can check Contact.MailingStreet.getDescribe().isPermissionable() && Contact.MailingStreet.getDescribe().getCompoundFieldName() == null

Attribution
Source : Link , Question Author : Christian Carter , Answer Author : Patlatus

Leave a Comment