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:

StageStage NumberPurpose
Pre-Validation10Before main platform validation (even before any security checks)
Pre-Operation20After validation, before database commit. You can modify input values.
Main Operation30Core platform operation (internal)
Post-Operation40After record is created. Output parameters available.

When to Use Pre-Validation or Pre-Operation#

Plugin StageUse Case
Pre-ValidationCross-record checks, throw early errors, or prevent unnecessary operations
Pre-OperationModify the Target entity before it’s saved to the database

Step 1: Create Plugin Project#

  1. Open Visual Studio → Create a Class Library (.NET Framework) project.

  2. 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#

  1. Connect to your CRM instance.

  2. Build and register this assembly by uploading your DLL.

  3. Register the step:

    • Message: Create
    • Primary Entity: new_test
    • Execution Mode: Synchronous
    • Stage: PreOperation (20)
  4. Set “Execution Order” if required.


Testing the implementation#

  1. Go to Dynamics 365 CE → Create a Test record.
  2. Populate data for adf_modifiedon, adf_modifiedby, adf_createdby fields and save the record
  3. 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/
Author
Anu Prakash S I
Published at
2025-07-05
License
CC BY-NC-SA 4.0