CreatedOn, CreatedBy, ModifiedOn and ModfiedBy– All you need to know to maintain history during Data Migration in Dynamics 365

These are the days of PowerApps. Canvas Apps, Model driven apps, flows and myriad of new features which are introduced lately or over the past couple of years. And yet in day-day jobs in our client projects we tend to argue over mundane things which in-fact I remember discussing during my initial days in CRM with 2011 version.

And one of them is data migration from one system to another maintaining their history. Whenever we talk about history, the bone of contention are the below four fields

  • CreatedOn
  • ModifiedOn
  • CreatedBy
  • ModifiedBy

We always suggest that any type of data operation should go through CRM SDK. Off course there are scenarios where you would perform DB to DB data migration but barring those scenarios it is always through SDK whether it is through batch JOB, plugin or SSIS Data adapter.

And here I was confidently updating my customer that we would be maintaining the history of all mentioned fields. However I get a stern objection saying while we can maintain the created on, we can’t do so for the remaining fields. And without wasting much time in argument I referred this wonderful blog written by the wonderful Aileen Gusni on the same topic way back in 2014 and it still holds good today! I was a big fan of her blogs during those early days in CRM and I still believe that she had one of the best content if not the best I have ever come across.

Coming back to the topic, the blog clearly mentions that you can maintain history for all of this. But still I was getting complaints that whatever code suggested there doesn’t work. And that is because we fail to understand the context where the code to set custom values for these four fields would work. If you have already understood the context, no need of reading further. Aileen’s blog is good enough!

But if you are still in doubt, here we dive deep.

Scenario 1: Create a console app and modify the fields using SDK.

var createEnt = new Entity("account");

createEnt["name"] = "Data Migration Create from Console";

createEnt["overriddencreatedon"] = new DateTime(2018, 03, 01);
createEnt["createdon"] = new DateTime(2017, 03, 01);
createEnt["modifiedon"] = new DateTime(2018, 03, 01);

// below is the GUID of one crm user named – CRM User 1
createEnt["modifiedby"] = new EntityReference("systemuser", Guid.Parse("67312B4B-9265-E911-A9BA-000D3A33BCD9"));
createEnt["createdby"] = new EntityReference("systemuser", Guid.Parse("67312B4B-9265-E911-A9BA-000D3A33BCD9"));


As of the day I am writing this blog, it is 12th of May, 2019.

Below is the snapshot of record I just created.

Let’s concentrate on the first field – “Created On”. As you can see CreatedOn is field is set to the custom value I set. But wait, it is set to 3rd of March, 2018. If you observe the above code sample, I have set two fields for “Created On” field.

createEnt["overriddencreatedon"] = new DateTime(2018, 03, 01);
createEnt["createdon"] = new DateTime(2017, 03, 01);

And it is the value of “overriddencreatedon” field which is taking effect here. So remember – “If you are trying to maintain the historical createdon value during data migration using CRM SDK from external application, it is the value of “overriddencreatedon” field which is important.

The other fields “ModifiedBy”, “ModifiedOn” and “CreatedBy” were set based on runtime values and whatever set in the code had no effect. So if you are trying to maintain historical data from these fields during data migration using SDK methods from external application, you would not be able to do so.


Scenario 2: Set values inside a plugin on pre-create.

Here I do the same code stuff but this time I do it in the pre-create of Account. Here is the code sample.

public void Execute(IServiceProvider serviceProvider)
             var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
             var target = (Entity)context.InputParameters["Target"];

            target["overriddencreatedon"] = new DateTime(2017, 03, 02);
             target["createdon"] = new DateTime(2017, 03, 01);
             target["modifiedon"] = new DateTime(2018, 03, 01);

   // Guid of CRM User 1
     target["modifiedby"] = new EntityReference("systemuser", Guid.Parse("67312B4B-9265-E911-A9BA-000D3A33BCD9"));
     target["createdby"] = new EntityReference("systemuser", Guid.Parse("67312B4B-9265-E911-A9BA-000D3A33BCD9"));


This time I create the record using UI. Below is the snapshot of the record after I create it.


Whoooo! All my custom values are taking effect here. And notice here, overriddencreatedon this time has no effect. It is the createdon value which is reflecting now. So all you need to do to maintain history for these four fields is set the value in the pre-create pipeline. Whether you are importing, creating from console or using SSIS data adapters, the plugin would fire and this would take effect.

Scenario 3: Set values inside a plugin on pre-update.

I am not going deep here. But this would perform the same like pre-create. I am not sure which scenario you would like to use pre-update to update these historical fields. But the just from the holistic point of view this would work exactly like pre-create.

Scenario 4: Using update Method of SDK.

If you are setting these fields using service.Update method of SDK, this would not take any effect. Even the created on won’t work this time unlike our first scenario no matter if you set the createdon or overriddencreatedon field.

Hope this helps next time you do data migration.

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit or reach out to us at

Our product offerings:

Role based views for Dynamics 365 (

CRM-Sharepoint Attachment uploader and metadata manager (

Record Cloner for Dynamics 365 (

Multiselect picklist for Dynamics 365 (

Leave a Reply