Thinking about how to migrate Dataverse Legacy to the new Dataverse connector as the depreciation date coming? Here is how I migrate it (remembered to always back up your flows before trying it and do it with your own risk).
The easiest way to know the difference is by creating the same exact flow with all those actions needed (Create, Update, Delete, Get By Row Id, and List):

Below is the legacy flow JSON:
{
"properties": {
"connectionReferences": {
"shared_commondataservice": {
"runtimeSource": "invoker",
"connection": {
"connectionReferenceLogicalName": "tmy_sharedcommondataservice_19e76"
},
"api": {
"name": "shared_commondataservice"
}
}
},
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
},
"$authentication": {
"defaultValue": {},
"type": "SecureObject"
}
},
"triggers": {
"manual": {
"metadata": {
"operationMetadataId": "1740d511-eb9d-43c2-bb25-4e3e08d87463"
},
"type": "Request",
"kind": "PowerApp",
"inputs": {
"schema": {
"type": "object",
"properties": {},
"required": []
}
}
}
},
"actions": {
"Add_a_new_row_(legacy)": {
"runAfter": {},
"metadata": {
"operationMetadataId": "f97ee139-be94-4e78-b8b6-639b0a855684"
},
"type": "OpenApiConnection",
"inputs": {
"host": {
"connectionName": "shared_commondataservice",
"operationId": "PostItem_V2",
"apiId": "/providers/Microsoft.PowerApps/apis/shared_commondataservice"
},
"parameters": {
"dataset": "https://org2d56f1ac.crm5.dynamics.com",
"table": "contacts",
"item/lastname": "Temmy",
"item/_parentcustomerid_type": "",
"item/isbackofficecustomer": false,
"item/adx_confirmremovepassword": false,
"item/creditonhold": false,
"item/msdyn_disablewebtracking": false,
"item/donotbulkemail": false,
"item/donotbulkpostalmail": false,
"item/donotemail": false,
"item/donotfax": false,
"item/donotpostalmail": false,
"item/donotphone": false,
"item/adx_identity_emailaddress1confirmed": false,
"item/followemail": true,
"item/msdyn_isminor": false,
"item/msdyn_isminorwithparentalconsent": false,
"item/adx_identity_locallogindisabled": false,
"item/adx_identity_lockoutenabled": false,
"item/adx_identity_logonenabled": false,
"item/marketingonly": false,
"item/adx_identity_mobilephoneconfirmed": false,
"item/participatesinworkflow": false,
"item/adx_profilealert": false,
"item/adx_profileisanonymous": false,
"item/donotsendmm": false,
"item/adx_identity_twofactorenabled": false,
"item/_ownerid_type": ""
},
"authentication": {
"type": "Raw",
"value": "@json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"
}
}
},
"Update_a_row_(legacy)": {
"runAfter": {
"Add_a_new_row_(legacy)": [
"Succeeded"
]
},
"metadata": {
"operationMetadataId": "a2759590-93b2-4318-aa35-372de4f403f5"
},
"type": "OpenApiConnection",
"inputs": {
"host": {
"connectionName": "shared_commondataservice",
"operationId": "PatchItem_V2",
"apiId": "/providers/Microsoft.PowerApps/apis/shared_commondataservice"
},
"parameters": {
"dataset": "https://org2d56f1ac.crm5.dynamics.com",
"table": "contacts",
"id": "a56a4006-9a0e-4e4f-8d86-ba1b2778f584",
"item/lastname": "Temmy",
"item/_parentcustomerid_type": "",
"item/_ownerid_type": ""
},
"authentication": {
"type": "Raw",
"value": "@json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"
}
}
},
"Delete_a_row": {
"runAfter": {
"Update_a_row_(legacy)": [
"Succeeded"
]
},
"metadata": {
"operationMetadataId": "4d121d02-db4f-4c3b-b1de-d021ca10bfb8"
},
"type": "OpenApiConnection",
"inputs": {
"host": {
"connectionName": "shared_commondataservice",
"operationId": "DeleteItem",
"apiId": "/providers/Microsoft.PowerApps/apis/shared_commondataservice"
},
"parameters": {
"dataset": "https://org2d56f1ac.crm5.dynamics.com",
"table": "contacts",
"id": "a56a4006-9a0e-4e4f-8d86-ba1b2778f584"
},
"authentication": {
"type": "Raw",
"value": "@json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"
}
}
},
"Get_row_(legacy)": {
"runAfter": {
"Delete_a_row": [
"Succeeded"
]
},
"metadata": {
"operationMetadataId": "c6f306bf-99b2-4d20-b66b-7a98c0b045a1"
},
"type": "OpenApiConnection",
"inputs": {
"host": {
"connectionName": "shared_commondataservice",
"operationId": "GetItem_V2",
"apiId": "/providers/Microsoft.PowerApps/apis/shared_commondataservice"
},
"parameters": {
"dataset": "https://org2d56f1ac.crm5.dynamics.com",
"table": "contacts",
"id": "a56a4006-9a0e-4e4f-8d86-ba1b2778f584"
},
"authentication": {
"type": "Raw",
"value": "@json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"
}
}
},
"List_rows_(legacy)": {
"runAfter": {
"Get_row_(legacy)": [
"Succeeded"
]
},
"metadata": {
"operationMetadataId": "0a7d3e04-9e1e-450a-b828-de565701fc3e"
},
"type": "OpenApiConnection",
"inputs": {
"host": {
"connectionName": "shared_commondataservice",
"operationId": "GetItems_V2",
"apiId": "/providers/Microsoft.PowerApps/apis/shared_commondataservice"
},
"parameters": {
"dataset": "https://org2d56f1ac.crm5.dynamics.com",
"table": "contacts",
"$top": 1
},
"authentication": {
"type": "Raw",
"value": "@json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"
}
}
}
}
},
"templateName": ""
},
"schemaVersion": "1.0.0.0"
}
And here is the new flow JSON:
{
"properties": {
"connectionReferences": {
"shared_commondataserviceforapps": {
"runtimeSource": "embedded",
"connection": {
"connectionReferenceLogicalName": "tmy_sharedcommondataserviceforapps_db083"
},
"api": {
"name": "shared_commondataserviceforapps"
}
}
},
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
},
"$authentication": {
"defaultValue": {},
"type": "SecureObject"
}
},
"triggers": {
"manual": {
"metadata": {
"operationMetadataId": "c675d7b4-f16a-47d4-ba50-6477c29b7d6b"
},
"type": "Request",
"kind": "PowerApp",
"inputs": {
"schema": {
"type": "object",
"properties": {},
"required": []
}
}
}
},
"actions": {
"Add_a_new_row": {
"runAfter": {},
"metadata": {
"operationMetadataId": "96efb6ea-fa12-4121-a23b-545eadf1f831"
},
"type": "OpenApiConnection",
"inputs": {
"host": {
"connectionName": "shared_commondataserviceforapps",
"operationId": "CreateRecord",
"apiId": "/providers/Microsoft.PowerApps/apis/shared_commondataserviceforapps"
},
"parameters": {
"entityName": "contacts",
"item/lastname": "Temmy Raharjo"
},
"authentication": {
"type": "Raw",
"value": "@json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"
}
}
},
"Update_a_row": {
"runAfter": {
"Add_a_new_row": [
"Succeeded"
]
},
"metadata": {
"operationMetadataId": "71366ba0-1754-4c34-9d70-22cbcc594cb9"
},
"type": "OpenApiConnection",
"inputs": {
"host": {
"connectionName": "shared_commondataserviceforapps",
"operationId": "UpdateRecord",
"apiId": "/providers/Microsoft.PowerApps/apis/shared_commondataserviceforapps"
},
"parameters": {
"entityName": "contacts",
"recordId": "a56a4006-9a0e-4e4f-8d86-ba1b2778f584",
"item/lastname": "Temmy"
},
"authentication": {
"type": "Raw",
"value": "@json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"
}
}
},
"Delete_a_row": {
"runAfter": {
"Update_a_row": [
"Succeeded"
]
},
"metadata": {
"operationMetadataId": "efadd439-c4f5-49da-b092-68be9a781b18"
},
"type": "OpenApiConnection",
"inputs": {
"host": {
"connectionName": "shared_commondataserviceforapps",
"operationId": "DeleteRecord",
"apiId": "/providers/Microsoft.PowerApps/apis/shared_commondataserviceforapps"
},
"parameters": {
"entityName": "contacts",
"recordId": "a56a4006-9a0e-4e4f-8d86-ba1b2778f584"
},
"authentication": {
"type": "Raw",
"value": "@json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"
}
}
},
"Get_a_row_by_ID": {
"runAfter": {
"Delete_a_row": [
"Succeeded"
]
},
"metadata": {
"operationMetadataId": "6e72fe43-3b72-4106-8875-61a02b6b2163"
},
"type": "OpenApiConnection",
"inputs": {
"host": {
"connectionName": "shared_commondataserviceforapps",
"operationId": "GetItem",
"apiId": "/providers/Microsoft.PowerApps/apis/shared_commondataserviceforapps"
},
"parameters": {
"entityName": "contacts",
"recordId": "a56a4006-9a0e-4e4f-8d86-ba1b2778f584"
},
"authentication": {
"type": "Raw",
"value": "@json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"
}
}
},
"List_rows": {
"runAfter": {
"Get_a_row_by_ID": [
"Succeeded"
]
},
"metadata": {
"operationMetadataId": "30c1c040-20fe-41e0-ade9-56f43e8b1ae1"
},
"type": "OpenApiConnection",
"inputs": {
"host": {
"connectionName": "shared_commondataserviceforapps",
"operationId": "ListRecords",
"apiId": "/providers/Microsoft.PowerApps/apis/shared_commondataserviceforapps"
},
"parameters": {
"entityName": "contacts",
"$top": 1
},
"authentication": {
"type": "Raw",
"value": "@json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"
}
}
}
}
},
"templateName": ""
},
"schemaVersion": "1.0.0.0"
}
If you compare those 2 JSONs, you can see that the new Dataverse connector are indeed simpler. I can see the legacy connector has some unnecessary attributes (In the create action, I just add Last Name, but somehow in the legacy flows adding more attributes that I not mentioned):

Here is my code to automatically migrate to the new Dataverse Action (you may be got an error when running using this tool as I’m making this one with my testing flow. So do it at your own risk):
using System.Collections;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Reflection;
using Newtonsoft.Json.Linq;
var appSettingsFilePath = Directory.GetCurrentDirectory() + "//appSettings.json";
var appSettings = JsonConvert.DeserializeObject<AppSettings>(File.ReadAllText(appSettingsFilePath));
var files = Directory.GetFiles(appSettings.WorkingDirectory, "*.*", SearchOption.AllDirectories)
.Where(s => Path.GetExtension(s).ToLowerInvariant() == ".json");
foreach (var filePath in files)
{
var originalText = File.ReadAllText(filePath);
// Minifying JSON
var obj = JsonConvert.DeserializeObject(originalText);
var minifyJson = JsonConvert.SerializeObject(obj, Formatting.None);
// Skip if no dataverse legacy
if (!originalText.Contains("\"shared_commondataservice\"")) continue;
minifyJson = minifyJson.Replace("\"shared_commondataservice\":{\"runtimeSource\":\"invoker\",", "\"shared_commondataservice\":{\"runtimeSource\":\"embedded\",");
minifyJson = minifyJson.Replace("shared_commondataservice", "shared_commondataserviceforapps");
minifyJson =
minifyJson.Replace($"\"connectionReferenceLogicalName\":\"{appSettings.DataverseLegacyConnectionName}\"",
$"\"connectionReferenceLogicalName\":\"{appSettings.DataverseConnectionName}\"");
minifyJson = ReplaceDatasetToId(minifyJson);
minifyJson = minifyJson.Replace("\"operationId\":\"PostItem_V2\"", "\"operationId\":\"CreateRecord\"");
minifyJson = minifyJson.Replace("\"operationId\":\"PatchItem_V2\"", "\"operationId\":\"UpdateRecord\"");
minifyJson = minifyJson.Replace("\"operationId\":\"DeleteItem\"", "\"operationId\":\"DeleteRecord\"");
minifyJson = minifyJson.Replace("\"operationId\":\"GetItem_V2\"", "\"operationId\":\"GetItem\"");
minifyJson = minifyJson.Replace("\"operationId\":\"GetItems_V2\"", "\"operationId\":\"ListRecords\"");
obj = JsonConvert.DeserializeObject(minifyJson);
var modifiedText = JsonConvert.SerializeObject(obj, Formatting.Indented);
File.WriteAllText(filePath, modifiedText);
Console.WriteLine("Replaced..");
}
string RemoveEmptyValues(string text)
{
var splitParameters = text.Split("\"item/").ToArray();
var result = new List<string>();
foreach (var parameter in splitParameters)
{
var splitValues = parameter.Split(":");
if (splitValues[0].StartsWith('"'))
{
result.Add(parameter);
continue;
}
if (splitValues.Length == 2 && splitValues[1].Contains("\"\"")) continue;
if (splitValues.Length > 2 && splitValues[1].Contains("\"\""))
{
splitValues[1] = splitValues[1].Replace("\"\"", "");
var tempText = string.Join(":", splitValues.Skip(1));
result.Add(tempText);
continue;
}
result.Add("\"item/" + parameter);
}
var temp = string.Join("", result);
return temp;
}
string ReplaceDatasetToId(string text)
{
var splitParameters = text.Split("\"parameters\":{").ToArray();
if (!splitParameters.Any(e => e.Contains("\"dataset\"") &&
e.Contains("\"table\"") && e.Contains("\"id\""))) return text;
var copySplitParameters = splitParameters.ToArray();
for (var i = 0; i < splitParameters.Length; i++)
{
var parameter = splitParameters[i];
var valid = parameter.Contains("\"dataset\"") &&
parameter.Contains("\"table\"");
if (!valid) continue;
var containsId = parameter.Contains("\"id\"");
var find = containsId ? "\"id\"" : "\"table\"";
var ended = parameter.IndexOf(find, StringComparison.CurrentCulture);
var findText = parameter.Substring(0, ended) + find;
var findTable = findText.IndexOf("\"table\"", StringComparison.CurrentCulture);
var findTableText = findText.Substring(0, findTable);
var result = parameter.Replace(findTableText, "")
.Replace("\"table\"", "\"entityName\"")
.Replace("\"id\"", "\"recordId\"");
copySplitParameters[i] = RemoveEmptyValues(result);
}
return string.Join("\"parameters\":{", copySplitParameters);
}
Console.ReadKey();
public class AppSettings
{
public string DataverseLegacyConnectionName { get; set; } = null!;
public string DataverseConnectionName { get; set; } = null!;
public string WorkingDirectory { get; set; } = null!;
}
Once done with the code, I exported my solution where it has the Flow that I needed (remembered to also include the new Dataverse connection – you can create a flow that uses the new Dataverse connector):

Once it is done, export the solution to unmanaged and extract the content inside the zip (you can use right-click> Extract all on the solution zip) because later on we will import the solution again and verify:

Then for the Console, you need to update the appSettings.json to reflect your needs:
{
"dataverseLegacyConnectionName": "tmy_sharedcommondataservice_19e76",
"dataverseConnectionName": "tmy_sharedcommondataserviceforapps_db083",
"workingDirectory": "C:\\Users\\Temmy Raharjo\\Desktop\\Flow\\Blog_1_0_0_2 - Copy"
}
Changed the connection names that you need to replace (from legacy connection to new Dataverse connection). And also you need to put your working directory. Once this is done, you can run the program and it will automatically replace the result for you!

The result:

You can get the full solution in this GitHub folder https://github.com/temmyraharjo/dynamics-crm-samples/tree/main/src/MigrateDataverseTools.