Thursday 30 July 2009

Some undocumented CRM attribute types

I was working on some custom plugin registration tools recently, and came across some undocumented attribute types. Several customisation entities (e.g. PluginAssembly, PluginType, SavedQuery) have an attribute called CustomizationLevel which has a value of 0 for system data, and 1 if it is custom or customised (according to the SDK).

The SDK documentation states this attribute is of type CrmNumber, so when writing a QueryExpression that selects only records with a CustomizationLevel = 1, it would seem reasonable to use something like:

qe.Criteria.AddCondition(new ConditionExpression("customizationlevel", ConditionOperator.Equal, 1));

However, this gives the error “Condition for attribute 'customizationlevel': expected argument(s) of type 'System.Byte' but received 'System.Int32' " (code 0x80040203 - Invalid Argument). Digging deeper I found that the field for the CustomizationLevel is stored in SQL as a tinyint (i.e. a single-byte integer), and that the AttributeTypes table in CRM has a corresponding AttributeType of tinyint.

So, despite the attribute being identified as a CrmNumber, any condition expressions need to pass values as a single-byte integer, not the documented four-byte integer. This is easily done by using the following:

qe.Criteria.AddCondition(new ConditionExpression("customizationlevel", ConditionOperator.Equal, (Byte) 1));

Being somewhat nosey, I thought to see what other attribute types there were. These can be easily found with the following SQL query:

Select * from AttributeTypes

In addition to tinyint, 2 similar types caught my attention – smallint and bigint (SQL Server data type names are not that imaginative). Following on from this, the following SQL query lists attributes of these types, which may cause similar problems to those above:

select e.name as Entity, a.name as Attribute, at.description as [Type]
from attribute a join entity e on a.entityid = e.entityid
join attributetypes at on a.attributetypeid = at.attributetypeid
where at.description in ('tinyint', 'smallint', 'bigint')
order by at.description, e.name, a.name

This yields the following results. The bigint attributes aren’t a concern, as these 2 attributes aren’t available via the CRM platform, but you could encounter some of the smallint types on UserSettings, in which case I expect you’d have to cast values to Int16.

EntityAttributeType
AsyncOperationsequencebigint
Subscriptioncompletedsyncversionnumberbigint
Organizationtokenexpirysmallint
UserSettingsadvancedfindstartupmodesmallint
UserSettingstimezonecodesmallint
UserSettingstimezonedaylightdaysmallint
UserSettingstimezonedaylightdayofweeksmallint
UserSettingstimezonedaylighthoursmallint
UserSettingstimezonedaylightminutesmallint
UserSettingstimezonedaylightmonthsmallint
UserSettingstimezonedaylightsecondsmallint
UserSettingstimezonedaylightyearsmallint
UserSettingstimezonestandarddaysmallint
UserSettingstimezonestandarddayofweeksmallint
UserSettingstimezonestandardhoursmallint
UserSettingstimezonestandardminutesmallint
UserSettingstimezonestandardmonthsmallint
UserSettingstimezonestandardsecondsmallint
UserSettingstimezonestandardyearsmallint
Organizationfiscalyeardisplaycodetinyint
Organizationtagmaxaggressivecyclestinyint
Organizationtrackingtokeniddigitstinyint
OrganizationUIcustomizationleveltinyint
PluginAssemblycustomizationleveltinyint
PluginTypecustomizationleveltinyint
SavedQuerycustomizationleveltinyint
SdkMessagecustomizationleveltinyint
SdkMessageFiltercustomizationleveltinyint
SdkMessagePaircustomizationleveltinyint
SdkMessageProcessingStepcustomizationleveltinyint
SdkMessageProcessingStepImagecustomizationleveltinyint
SdkMessageProcessingStepSecureConfigcustomizationleveltinyint
SdkMessageRequestcustomizationleveltinyint
SdkMessageRequestFieldcustomizationleveltinyint
SdkMessageRequestInputcustomizationleveltinyint
SdkMessageResponsecustomizationleveltinyint
SdkMessageResponseFieldcustomizationleveltinyint

0 comments: