Monday, May 13, 2013

CRM 2011 - Migrating Notes while maintaining history information

Notes in Dynamics CRM 2011 typically provide information about the note text, along with details of when the note was created (or modified) and by whom. If we think of how Notes are used, I think we can all agree that the history information (whom and when) is a critical component of the Note record.

The process of importing Notes and Attachments using the Data Import Wizard is pretty straightforward for the most part. The import wizard however does not map all possible attributes available in the system. For example, we cannot set the created by, modified on or modified by data using the import wizard. The only attribute that can be set (overridden) is the created on field. How do we solve this issue to make sure we are migrating Notes correctly? Here is one option to consider.

Business Case:
Migrate Notes into CRM 2011 with the right modified by, created by and modified on information.

Design:
Use the data import wizard to import the note. Set created on and owner value for the Note using the wizard. Create a plugin that fires on Note create, which sets the value of modified by and modified on.

Implementation Details:

1. Create csv's for note and associated record, if necessary. In my scenario, I am creating a new case and attaching 2 notes to the case.

Set the value of the Owner and Record Created on tabs to the last modified user and modified on datetime (Note that I am assuming the owner to be last modified user for simplicity sake). Here is a link for a more detailed look on importing data into crm 2011.






















2. During the import process using the wizard, map the owner field and the created on field in annotation entity to the owner column and record created on column respectively in the csv.






























3. Import the data. Save the data map to use for import. Once imported, this is what the note details would look like. Notice that the created by, modified by and modified on values take on the values of the person doing the import, and the time of the import.












4. To get the right values for the Note fields, we need a plugin that fires on a pre-create of a note/ annotation. Here is a code snippet to get you started:

                // Verify that the target entity represents an note.
                // If not, this plug-in was not registered correctly.
                if (entity.LogicalName == "annotation")
                {
                    tracingService.Trace("Entity is an annotation");

                    //update modified on and modified by values

                    try
                    {

                        if (entity.Attributes.Contains("createdon") && entity.Attributes.Contains("ownerid"))
                        {
                            DateTime createdon1 = entity.GetAttributeValue("createdon");

                            EntityReference ownerId = entity.GetAttributeValue("ownerid");

                            tracingService.Trace("Created on and owner Id values: " + createdon1.ToString() + " " + ownerId.ToString());

                            //set modified on
                            if (entity.Attributes.Contains("modifiedon") == false && string.IsNullOrEmpty(createdon1.ToString()) == false)
                            {
                                entity.Attributes.Add("modifiedon", createdon1);
                            }
                            else if (entity.Attributes.Contains("modifiedon") == true && string.IsNullOrEmpty(createdon1.ToString()) == false)
                            {
                                entity["modifiedon"] = createdon1;
                            }

                            //set modified by
                            if (entity.Attributes.Contains("modifiedby") == false && string.IsNullOrEmpty(ownerId.ToString()) == false)
                            {
                                entity.Attributes.Add("modifiedby", ownerId);
                            }
                            else if (entity.Attributes.Contains("modifiedby") == true && string.IsNullOrEmpty(ownerId.ToString()) == false)
                            {
                                entity["modifiedby"] = ownerId;
                            }   
                        }


                    }
                    catch (Exception ex)
                    {
                        throw new InvalidPluginExecutionException("An error occured updating the Modified By and Modified On in the Annotation record ", ex);
                    }
                }

Let me walk through the code a bit here. During the create of the annotation record, I set the modified by and modified on value to the owner and created on values from the csv file. The assumption here is that the created on and modified on are the same, which might not be true in all cases. At a minimum, this approach will get the last modified date/ user id of the note.

Here is what the history information of the note looks like once the plugin is registered and a step added for Annotation pre-create:












Notice that the edited information is now populated from the import file rather than getting filled out by the system.

Bonus Tip:
Though this approach makes the most sense to use for importing Notes, you can follow a similar path if the goal is to carry over modified on/by entity data from one system to the other. Additionally, if you don't want to use the created by as you modified by, create a new date/time attribute and map your modified on date to that custom field. Then, in the plugin, use that value to set the modified information.

Thanks for reading!

1 comment:

  1. This is very nice blog, I like this a lot. Businessmen are waking up to the fact that their leads are useless unless and until they can get money out of them.

    ReplyDelete