Migrating CRM Activity Entities Properly

16 September 2016
Daniel Cai

When it comes to the migration of CRM activity entities, there are quite a few challenges lying ahead. Until they are fully addressed, you really can't say for sure that your migration has been done correctly or properly. Let's first discuss some of the facts around CRM activity entities.

  • Activity is actually a special group of CRM entities, instead of just one. When you create a new entity in CRM, you can designate the entity to be an activity entity, which will inherit the standard behaviors of CRM activity entities.
  • Each activity entity has an actual CRM entity name, such as email, phonecall, appointment, etc. However, there is also an umbrella entity that is called activitypointer, which contains a consolidated list of all activity records.
  • CRM activity entity can contain one or more activityparty fields which are also known as party list fields. Those are a special kind of CRM fields, as CRM can store multiple party values in one single field.
  • As mentioned above, CRM activityparty fields can contain multiple parties in a single field. The party can be an account, contact, lead, queue, system user record, or even just a plain email address. In the case that the party is an account, contact, lead, queue or system user record, it is essentially a lookup value, which is identified by the lookup type and then a lookup GUID value. For instance, a party can be an account with a GUID "{F95E633C-3FDC-45BA-BACA-32B9878106C7}".
  • CRM displays activity records on the activity wall (or social wall) using the sequence based on the values in the modifiedon field, so a newer activity record appears before the older ones.

With that being said, the above mentioned facts naturally lead to the following two main challenges for its data migration effort.

  1. For the activityparty fields, you would have to find a way to use different strategies for different lookup entities. For instance, you would typically do a full migration of account, contact, lead and queue entities, so the CRM destination component can really just take GUID values for those entities when constructing a partylist value. However, if one of the parties is a system user, then it is a totally different situation, as CRM instances do not typically share the same systemuserid (GUID) for the same CRM user. In order to migrate those system users used in activityparty fields, there is a need for some sort of lookup strategy so that we can find the user's ID in target CRM system when constructing the activityparty fields.
  2. As we mentioned above, CRM display activitys records on the activity wall in a descending order of the modifiedon field. However this particular field is not write-able in the CRM destination component, therefore you can't bring the old modifiedon values to the new system, as CRM defaults the field to the datetime of the last write action - which is when the migration happens. The problem is, if the activity is not migrated in the right order, then everything on the activity wall can be out-of-sync from the source system. You might think this is easy, you just have to sort by modifiedon field in the source component. But the problem is, activity wall is made up of records from all activity entities, not just a single one. Sorting each individual entity would not help with the situation.

For the above first issue, the solution is fairly simple if you use the Text Lookup feature offered in our software. For each activityparty field, you would set it up to perform a text lookup. We have designed our software to output a JSON data structure in the CRM source component which contains PartyId, Type (the party type), and Name (the party's name). This structure makes it possible to perform a Text Lookup for any involved party entities, and the CRM destination component can use this data structure as the input without problems. As we just mentioned, for account, contact, lead, queue entities, we usually do a full migration, so that we can assume all those party IDs are already been in the target system for them, in which case we opt out from performing the Text Lookup. For systemuser entity, we will perform a lookup on the entity's primary field (which is the only available lookup option when working with activityparty fields - as the JSON structure only contains Name, no other text fields are available). The following is a typical setup for a partylist field which handles the challenge that we have just discussed. 

PartyList Field

For the second issue, our solution is to first migrate all activity entities using Create or Upsert action in the CRM destination component. In this step, we have one data flow task for each activity entity so that we can do a full migration of all necessary fields. As you know, you can't create a CRM entity record with an inactive status. So in this step, we have excluded the statecode/statuscode fields in the mapping, because they require a separate write action nonetheless (which will later be used to update the activity records so that we can set the modifiedon field in the right sequence).

Migrate Activity Entities

As you can see from the above screenshot, we have tried to manage the dependencies between those entities, we migrate campaignactivity entity first, then those common activity entities (phonecall, task, email, etc.), and followed by the campaignresponse entity.

After the above is done, we then perform a final update of all activity records using a new data flow task which is attached right after the above SSIS sequence container.

Final Touch of Activity Entities

The following is what's inside the last data flow task shown above. It is a very simple data flow. Basically we are reading from activitypointer entity (instead of individual entities this time), and then send all records to a CRM destination component to perform an update of the statecode, statuscode fields. Note that in the FetchXML query of the source component we are sorting the results by the modifiedon field, so that we can have a sorted output for the destination component which will process the all records in a sorted order that is supposed to be the same as the source system.

Read activitypointer entity

The following is the screenshot of the destination component. As you can see, we are again working with the activitypointer entity, and we perform an update based on the primary key.

Write activitypointer entity (General Page)The following is the column mapping page of the destination component. You can see that we are actually only updating the statecode and statuscode fields in this step.

rite activitypointer entity (Column Mappings)

With above setup and configurations, you should be able to migrate the activity records in the right sequence.

In addition to the above two main challenges, there are also some challenges for the recurring appointment records, which have been addressed in the blog post written by my colleague - Chen Huang.

This basically summarizes the challenges around CRM activity entity migration, and the techniques that you can use in your data migration project. For your convenience, this whole migration process is demonstrated in the sample CRM migration package that we have just shared. I hope you find this useful.

Archive

October 2024 1 September 2024 1 August 2024 2 July 2024 1 June 2024 1 May 2024 1 April 2024 2 March 2024 2 February 2024 2 January 2024 2 December 2023 1 November 2023 1 October 2023 2 August 2023 1 July 2023 2 June 2023 1 May 2023 2 April 2023 1 March 2023 1 February 2023 1 January 2023 2 December 2022 1 November 2022 2 October 2022 2 September 2022 2 August 2022 2 July 2022 3 June 2022 2 May 2022 2 April 2022 3 March 2022 2 February 2022 1 January 2022 2 December 2021 1 October 2021 1 September 2021 2 August 2021 2 July 2021 2 June 2021 1 May 2021 1 April 2021 2 March 2021 2 February 2021 2 January 2021 2 December 2020 2 November 2020 4 October 2020 1 September 2020 3 August 2020 2 July 2020 1 June 2020 2 May 2020 1 April 2020 1 March 2020 1 February 2020 1 January 2020 1 December 2019 1 November 2019 1 October 2019 1 May 2019 1 February 2019 1 December 2018 2 November 2018 1 October 2018 4 September 2018 1 August 2018 1 July 2018 1 June 2018 3 April 2018 3 March 2018 3 February 2018 3 January 2018 2 December 2017 1 April 2017 1 March 2017 7 December 2016 1 November 2016 2 October 2016 1 September 2016 4 August 2016 1 June 2016 1 May 2016 3 April 2016 1 August 2015 1 April 2015 10 August 2014 1 July 2014 1 June 2014 2 May 2014 2 February 2014 1 January 2014 2 October 2013 1 September 2013 2 August 2013 2 June 2013 5 May 2013 2 March 2013 1 February 2013 1 January 2013 1 December 2012 2 November 2012 2 September 2012 2 July 2012 1 May 2012 3 April 2012 2 March 2012 2 January 2012 1

Tags