Category: Development

Migrating / Importing data and maintaining Created By, Modified By and Modified On

Migrating / Importing data and maintaining Created By, Modified By and Modified On

When importing or migrating data to a Dynamics 365 / CRM environment you cannot migrate the fields Created By, Modified By and Modified On. Most customers won’t bother about it until it comes down to the migration of ‘old’ activities. By default, the Social Panes show activities sorted on the Modified On date. So when you migrate data and all activities have ‘today’ as the Modified On date, you’ll get problems with the sorting of activities.

Migrating the data and setting the fields

As you know, it’s not possible to set the values of the Created By, Modified By and Modified On date. That is when you try to set this data directly. Lucky for us, when using the SDK it is actually possible to set the values of those fields. The solution contains a plugin that does this:

  • At the creation of a record, check if the field ‘dnbs_overriddencreatedby’ contains a value. If so, set the field createdby to that value.
  • At updating a record, check if the field ‘dnbs_overriddenmodifiedby’ contains a value. If so, set the field modifiedby to that value.
  • At updating a record, check if the field ‘dnbs_overriddenmodifiedon’ contains a value. If so, set the field modifiedon to that value.

In order to make this work for your data migration or data import, just make sure you set the values of the fields ‘dnbs_overriddencreatedby’, ‘dnbs_overriddenmodifiedby’ and ‘dnbs_overriddenmodifiedon’. These are the schema names of the fields. The display names are: Overridden Created By, Overridden Modified By and Overridden Modified On. When you import the solution, these fields are available on these entities:

  • Appointment
  • E-mail
  • Letter
  • Phonecall
  • Taks

The solution is extensible

The plugin inside the solution is setup to fire off on all entities. This means that you can extend the use of this plugin to all other entities. When you want to use the same method on the Account entity, for instance. You just need to make sure you create these fields on that entity. The schema names of those fields must exactly match these names.

  • dnbs_overriddencreatedby as a Lookup to the User entity;
  • dnbs_overriddenmodifiedby as a Lookup to the User entity;
  • dnbs_overriddenmodifiedon as a Date and Time field.

Don’t forget to delete the solution!

When you are done with migrating or importing your data, don’t forget to delete the solution! As you have seen above, the plugin fires off at all updates. This is a loss to your performance and also you might get into trouble with the Modified By and Modified On fields not being updated right.

Download your solution here

Download

The source code can be found here

https://github.com/marcgerner/D365ActivityMigration

Workaround for double update on statecode change via WebAPI

Workaround for double update on statecode change via WebAPI

The new WebApi of Dynamics CRM 2016 has some strange behavior when you only update the state code. You would expect that there would be one update to the record, but when you inspect the audit logs, there are two updates to the record. First there’s an update to set the state of the record the the state it already has. The second update to the record changes it to the actual state. This is both at on-premise and Online versions of Dynamics CRM.

A detailed post on this issue can be found at this blog post of my colleague Martijn Eikelenboom. As this issue is a real pain with one of my own implementations, I created a ticket with Microsoft to find if this is a bug or expected behavior. Because my customer couldn’t wait for a bugfix, I have created a workaround.

The code that activates the double update

At first, I wrote code to update the statecode and statuscode on a record. See the code below.

function setStatus(statusReasonValue, stateValue) {
    var entitdyId = Xrm.Page.data.entity.getId();
    var entity = {};
    entity.statuscode = statusReasonValue;
    entity.statecode = stateValue;

    $.ajax({
        type: "PATCH",
        contentType: "application/json; charset=utf-8",
        datatype: "json",
        url: Xrm.Page.context.getClientUrl() + "/api/data/v8.0/mg_orders(" + entitdyId.substring(1,37) + ")",
        data: JSON.stringify(entity),
        beforeSend: function (XMLHttpRequest) {
            XMLHttpRequest.setRequestHeader("OData-MaxVersion", "4.0");
            XMLHttpRequest.setRequestHeader("OData-Version", "4.0");
            XMLHttpRequest.setRequestHeader("Accept", "application/json");
        },
        async: false,
        success: function (data, textStatus, xhr) {
            //Success - No Return Data - Do Something
            Xrm.Page.ui.close();
        },
        error: function (xhr, textStatus, errorThrown) {
            alert(textStatus + " " + errorThrown);
        }
    });
}

The workaround

I needed an other way to change the status of the record and thought of workflow. When changing the status by using workflow, there is only one update instead of two. Therefor, at first my workaround was to create an Action process with the statuscode as an incoming variable. Second I have changed the javascript to call the Action with the proper statuscode and third: the Action does the trick! Also I used Process 2.0 as JavaScript library. You’ll find what you need down here. Good luck updating the statuscode!

Screenshot of the Action

action-process-update-statecode

The new JavaScript

function setStatus(statusReasonValue, stateValue) {
    debugger;
    Process.callAction(
    "mg_SetOrderState",
    [{
        key: "Target",
        type: Process.Type.EntityReference,
        value: new Process.EntityReference("mg_order", Xrm.Page.data.entity.getId())
    },
    {
        key: "StatusCode",
        type: Process.Type.Int,
        value: statusReasonValue
    }],
    function (params) {
        // Success
        Xrm.Page.ui.close();
    },
    function (e, t) {
        // Error
        alert(e);

        // Write the trace log to the dev console
        if (window.console && console.error) {
            console.error(e + "\n" + t);
        }
    });
}