In previous versions of CRM, creating realtime calculated fields involved a plugin that listened to the global Execute message (and optionally RetrieveMultiple if you wanted to handle filter criteria) – to handle FetchXml requests. The remaining messages (Retrieve, RetrieveMultiple, Update, Create) can be registered for the specific Entity, so you are not gumming up CRM with global plugins.
Some of the neat new features of CRM 2011 greatly complicate the process of creating a calculated field – your Plugin now must be registered globally for Retrieve, RetrieveMultiple and Execute; and there are three different query types to handle.
These are my research notes from building a plugin that allows for functionality similar to the “Customer” lookup in the built-in entities. It would be easy enough to sit on the Post-Stage event, look through the Result and use a retrieve for each record to get the calculated value. This would quickly degrade system performance – instead my solution modifies the query in the Pre-stage to include all necessary columns, then uses the data in the result to update the calculated field. It requires significantly more code, but is far more scalable.
1. Execute Message
I haven’t yet determined all the cases that Execute is called, but it is for sure called when the legacy webservice is used to perform an ExecuteFetch (such as when using Stunnware tools). It is also fired now and again by the UI (but not for normal grids – almost everything uses RetrieveMultiple now)
In the Pre-Stage, you must look for the “FetchXml” value in the InputParameters. If it is there, use your Xml parser / modifier of choice to look through it for any instances of your entity, then for each entity instance, check for your calculated field (these can be nested arbitrarily deep). If it contains the field, add your required source columns to Xml, and put the FetchXml back into the InputParameters.
The ResultXml on the Post-Stage is flat, and columns from Linked Entities are given a prefix. The prefix comes from the link-entity – it is the alias if one is specified, or the “to” attribute. (Caveat: If aliases are not used in a fetch, and there are multiple link-entities off attributes with the same name, the result will have duplicate column names. The UI always adds aliases.)
2. RetrieveMultiple Message
RetrieveMultiple is powered by a Query, and that query can be one of QueryExpression, QueryByAttribute, or FetchExpression. The query is in the InputParameter[“Query”], and is of type QueryBase.
In the pre-stage, check that query.EntityName is the correct entity; check query.ColumnSet for your calculated field, adding any required fields to the ColumnSet.
Next, recurse through the LinkEntities, checking the LinkToEntityName and the Columns for each.
In the post-stage, the result is in OutputParameters[“BusinessEntityCollection”] which is of type EntityCollection. Each record is an Entity, and all fields from linked entities are in the Attributes collection (similar to Fetch), prefixed for links. The prefix is either the alias of the LinkEntity, or if the alias is blank it is the entityname followed by a sequence number (eg “contact1.fullname”, “contact1.firstname” “account2.name”. The sequence number is assigned to each LinkEntity based on the order it occurs in the LinkEntity Tree.
(Note: to be complete, something similar should be done for the Orders, so that you can sort by your calculated column)
- Account (no prefix)
- Contact (contact1.<attribute>)
- Contact [alias shipper] (shipper.<attribute>)
- User (systemuser3.<attribute>)
- BusinessUnit (businessunit4.<attribute>)
This is better and worse than the old fetch method. It guarantees that prefixes are unique, but it requires you to traverse the entire LinkEntity tree in order to know what the resulting column name will be.
In your result, you simply do Entity[“calculatedFieldName”] = Entity[“sourceFieldName”].
The simplest of all – there is no nesting, no links, no related fields. You only have to check the ColumnSet (and optionally Orders).
All the same complexity as the QueryExpression, except you have to process FetchXml in the Pre-Stage. The Result works the same as with QueryExpression.
3. Retrieve Message
This is by far the most complicated message thanks to the RelatedEntitiesQuery property of the RetrieveRequest. I haven’t determined if / when this is used by the UI. In most cases it will be null, and you only need to worry about InputParameters[“ColumnSet”]. If InputParameters[“RelatedEntitiesQuery”] is populated, it is a keyed value collection keyed on a “Relationship” – the root of a related entity query must be part of an existing relationship. However, each query in the bag can have LinkEntities – so essentially the RelatedEntitiesQuery is a collection of multiple RetrieveMultiples attached to the record. It is a mess.
In the output, the returned Entity contains a field called RelatedEntities – this is a collection of entities again keyed on the relationship. Each of the relationship queries must be handled separately as the column aliases are specific to the query.
I’ve encountered several discussion and blog postings about this topic, and they are generally vague or incomplete. Suffice it to say handling all ways in which a field can be “hit” in CRM 2011 is daunting.