374 words
2 minutes
Migrate data and preserve Dynamics 365 CE System Fields

Migrate data and preserve Dynamics 365 CE System Fields
I came across a requirement to migrate data using Azure Data Factory from On-Premises to online version of Dynamics 365 CE by preserving the existing System Field values like createdby
, createdon
, modifiedby
, modifiedon
. I will walk you through the steps which I have followed to implement Pre-Operation plugin on Create to capture and override system fields with custom value (existing value from on-premises).
Plugin Execution Pipeline Overview
On Create of a record, Dynamics 365 executes plugins in stages:
Stage | Stage Number | Purpose |
---|---|---|
Pre-Validation | 10 | Before main platform validation (even before any security checks) |
Pre-Operation | 20 | After validation, before database commit. You can modify input values. |
Main Operation | 30 | Core platform operation (internal) |
Post-Operation | 40 | After record is created. Output parameters available. |
When to Use Pre-Validation or Pre-Operation
Plugin Stage | Use Case |
---|---|
Pre-Validation | Cross-record checks, throw early errors, or prevent unnecessary operations |
Pre-Operation | Modify the Target entity before it’s saved to the database |
Step 1: Create Plugin Project
-
Open Visual Studio → Create a Class Library (.NET Framework) project.
-
Install NuGet package:
Install-Package Microsoft.CrmSdk.CoreAssemblies
Step 2: Write Pre-Operation Plugin
public void Execute(IServiceProvider serviceProvider)
{
// Get the tracing service
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
// Get the plugin execution context from the service provider
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
// Check if the plugin is registered for the Create message and Pre-Operation stage
if (context.MessageName.ToLower() == "create" && context.Stage == 20)
{
// Verify that the Target is an Entity
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
// Check if adf fields exist and map them to standard fields
if (entity.Contains("adf_modifiedon"))
{
entity["modifiedon"] = entity["adf_modifiedon"];
}
if (entity.Contains("adf_modifiedby"))
{
entity["modifiedby"] = entity["adf_modifiedby"];
}
if (entity.Contains("adf_createdby"))
{
entity["createdby"] = entity["adf_createdby"];
}
//Trace
tracingService.Trace($"Pre-Operation-Create on {entity.LogicalName} is completed.");
}
}
}
Step 3: Build & Register Plugin Using Plugin Registration Tool
-
Connect to your CRM instance.
-
Build and register this assembly by uploading your DLL.
-
Register the step:
- Message:
Create
- Primary Entity:
new_test
- Execution Mode:
Synchronous
- Stage:
PreOperation (20)
- Message:
-
Set “Execution Order” if required.
Testing the implementation
- Go to Dynamics 365 CE → Create a Test record.
- Populate data for
adf_modifiedon
,adf_modifiedby
,adf_createdby
fields and save the record - Check if the system fields are populated with custom values.
Sample Input using WebApi
var data = {
"adf_CreatedBy@odata.bind": "/systemusers(35e0d39a-d19b-f011-bbd2-002248ee5962)",
"adf_ModifiedBy@odata.bind": "/systemusers(35e0d39a-d19b-f011-bbd2-002248ee5962)",
"adf_modifiedon": new Date("1991/1/1").toISOString(),
"overriddencreatedon": new Date("1991/1/1").toISOString(),
"new_name" : new Date("1991/1/1").toISOString()
};
Xrm.WebApi.createRecord("new_test", data).then(
function success(result) {
console.log("Record created with ID: " + result.id);
},
function (error) {
console.log(error.message);
}
);
Sample Result
Migrate data and preserve Dynamics 365 CE System Fields
https://crmte.ch/posts/oobfielddatamigrate/