Tracking Changes in Dynamics CRM 2015 Update 1

Ahmed Anwar, 25 May 2015

Tracking changes is a new feature introduced in CRM online. Tracking changes is important when performing data synchronisation between CRM and other systems. In this article, I'll explain how CRM can detect changes in records.

One day your boss asked you to develop a tool that runs every day to synchronise changed/updated invoices from CRM to Dynamics GP. You start to write some code and you suddenly realise that your tool is not aware of the changes happening in CRM. When you query the invoices from CRM, you can't determine which one has been updated, created or deleted. You ONLY need to post new or updated invoices. If an invoice is deleted, it should be deleted from Dynamics GP as well. Assuming you have not heard or developed applications on the Microsoft Sync Framework, Tracking Changes in CRM helps you to spot the changed data since creation or since last sync. Tracking changes can reduce the network traffic dramatically, reduce issues with duplicate records and reduce your code complexity to the minimum.

In the diagram below, I show the direction of the data flow of Contacts from CRM to GP only. The tool pulls data from CRM and pushes it to GP.


Looking at the above diagram tells us how the tool would synchronises data from CRM to GP and not the other way around, in my example, I synchronise contacts.

The tool should handle the following cases:

  1. Jon Snow is a record that exists in CRM and GP and it has not changed, so there is no need to update it.
  2. Stannis B. has been updated in CRM but not in GP. This record should be included in the change set.
  3. Arrya is a record exists in GP but not in CRM. It means that a user has deleted it in CRM. This record should be deleted in GP as well.
  4. Stark is a record exists in CRM but not in GP. This record should be created in GP.
  5. Tyrion L. is the same case as Stannis B., this record should be updated in GP.


RetrieveEntityChangesRequest class is all you need to detect changes that happened to all records.
But before you start consuming this class in your code, make sure to enable Change Tracking option under the Entity you want synchronise.

To instantiate an object of RetrieveEntityChangesRequest you would need to set four parameters

RetrieveEntityChangesRequest trackChangesRequest = new RetrieveEntityChangesRequest
{
EntityName = "contact",
Columns = new ColumnSet("firstname"),
PageInfo = new PagingInfo(),
DataVersion = string.Empty
};

Looks familiar? Yes, because this request retrieves changes so you will need to set the entity schema name, the columns or fields, paging information in case you have large number of records and the last important parameter is the DataVersion. This parameter plays a big role in synchronizing data. I'll explain how to process the changes and then I'll talk about the DataVersion, but first let me show you the response of the request.

The EntityChanges contains Changes and DataToken. To loop through all changes, use this code snippet:

if (trackChangesResponse.EntityChanges.Changes.Count > 0)
{
foreach (var change in trackChangesResponse.EntityChanges.Changes)
{
if (change is NewOrUpdatedItem)
{
NewOrUpdatedItem changedItem = (NewOrUpdatedItem)change;
Entity changedRecord = changedItem.NewOrUpdatedEntity;

if (changedRecord != null)
{
string firstName = changedRecord.GetAttributeValue<string>("firstname");
string dataToken = trackChangesResponse.EntityChanges.DataToken;
string changedType = changedItem.Type.ToString();

Console.WriteLine("DataVersion={0} ChangeType={1} FirstName={2}",
dataToken, changedType, firstName);
}
}
}
}


In CRM I only have four records as shown:

After running the code, I got four changes:


   

As you can see I printed three parameters, DataVersion as a string and ChangeType as an enum and the FirstName field of the record. The ChangeType tells you the type of the change.


Let's talk about the DataVersion in deep.
When I passed string.empty to DataVersion, the response retrieved all records from CRM and new value of the DataVersion= 826923!05/17/2015 22:51:13. As you can see it is composed of a number and a formatted Date and Time. In fact, we are not interested in the data. All we need is to store this value after each successful sync and pass it with each new request.

Whenever changes happen in records, these records will be associated to a new DataVersion. This DataVersion holds or carries all detected changes.

I wanted to test if I am allowed to use old DataVersion values. I have created a record in CRM and executed the request then stored the DataVersion, repeated this process multiple times. Then I executed a request and passed all old DataVersions and printed the result.



607435!05/17/2015 Stark
607435!05/17/2015 Stannis B.
607435!05/17/2015 Jon Snow
607439!05/17/2015 Stannis B.
607439!05/17/2015 Jon Snow
607443!05/17/2015 Jon Snow

As you can see, each DataVersion holds at least one record or more. But, if you only care for retrieving the latest changes to synchronise with other systems, then use the latest DataVersion.

Two things to remember when using RetrieveEntityChangesRequest:

  1. If you don't have a DataVersion, pass an empty string, then you'll get the latest DataVersion and all records as well.
  2. If any record in CRM is created, updated or deleted and you passed a DataVersion, you'll get a new DataVersion.

I'd highly recommend to experiment and play around it to understand how it works in action.