如何在Dataverse迁移中保留createdon、createdby、modifiedon和modifiedby?

问题描述 投票:0回答:1

在尝试了 SSIS 和 KingswaySoft 后,我选择编写一个控制台应用程序来迁移我的 Dataverse 表。 事实证明,与无代码/低代码方法相比,代码对我来说更熟悉并且更容易。 我遇到的一个问题是保留源记录中的用户/日期戳。 迁移时,这些值会被系统覆盖。

我找到了一种 OOTB 方法来覆盖

createdon
,但该方法并不全面,并且不适用于所有 4 个领域。

migration dynamics-crm dataverse kingswaysoft
1个回答
1
投票

经过大量研究和实验尝试以其他方式解决此问题,我编写了一个 RecordStamps 插件。 我将其连接到每个正在迁移的表的创建/更新操作,特别是预操作阶段。

我创建了一个用于迁移目的的中间表,称为迁移元。 在其中我创建了 Meta Created On、Meta Created By、Meta Modified On、Meta Modified By,所有这些都是为了确保列名称与系统更新的列名称不同。我还将主要名称字段命名为实体名称。

在迁移应用程序中,在迁移任何记录之前,我执行以下逻辑:

      //cache meta for use in RecordStamps Plugin.
      try {
        var mm = new Entity("crab9_migrationmeta", rec.Id);
        mm["crab9_entityname"] = rec.LogicalName;
        foreach (var key in new string[] { "modifiedby", "modifiedon", "createdby", "createdon" }) {
          mm[$"crab9_meta{key}"] = rec.Contains(key) ? rec[key] : null;
        }
        var found = false;
        try {
          this.targetDb.Retrieve(mm.LogicalName, mm.Id, new ColumnSet(false));
          found = true;
        } catch {
        }
        if (found) {
          this.targetDb.Update(mm);
        } else {
          this.targetDb.Create(mm);
        }
      } catch (Exception ex) {
        throw new Exception("Unable to set meta.", ex);
      }

我将源记录元数据值保存到这个表中,以便跟踪每条迁移的记录。 回想一下,GUID 是全局唯一的。保存元数据后,我将记录从源迁移到目标 Dataverse 环境。

RecordStamps 插件拦截创建/更新,使用 Id 和实体名称从迁移元表中检索靶心命中,然后在写入之前替换这些事实。

using Microsoft.Xrm.Sdk.Query;

namespace RecordStamps {

  using System;
  using Microsoft.Xrm.Sdk;

  public class RecordStampsPlugin : IPlugin {
    public static readonly string[] fields  = new string[] { "createdon", "createdby", "modifiedon", "modifiedby" };

    public void Execute(IServiceProvider serviceProvider) {
      var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
      var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
      var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
      var service = serviceFactory.CreateOrganizationService(context.UserId);
      var target = (Entity)context.InputParameters["Target"];

      if (context.Stage == 20) {
        try {
          tracingService.Trace("Checking record stamps at {1} for {0}", Tracing.Show(target), context.MessageName);

          var mm = service.Retrieve("crab9_migrationmeta", target.Id, new ColumnSet(true));
          if (mm != null) {
            if (mm["crab9_entityname"] != target.LogicalName) {
              throw new Exception("Meta entity name does not match target.");
            }
            tracingService.Trace("Applying record stamps {0}", Tracing.ShowAll(mm));
            foreach (var key in fields) {
              var mkey = $"crab9_meta{key}";
              if (mm[mkey] != null) {
                target[key] = mm[mkey];
                tracingService.Trace("Applied {0} => {1}", key, Tracing.Show(target[key]));
              }
            }
          }
        } catch (Exception ex) {
          tracingService.Trace("Error {0}", Tracing.Show(ex));
        }
      }
    }
  }
}

这个插件逻辑可能会有一些迭代,但到目前为止它运行良好。

Tracing.Show
是用于漂亮打印的自定义逻辑。

我提到了创建/更新。 我发现我不能只在目标环境中创建从源获取的非活动记录。 我必须首先将它们迁移为活动状态,然后稍后将它们设置为非活动状态。

迁移元表的额外好处是可以轻松撤消迁移,因为您迁移的所有内容都会被跟踪。 如果您想捕获与迁移相关的任何其他内容,您还可以添加其他字段。

在迁移应用程序中,我不费心修复迁移用户的元(表:

systemuser
)。 我首先迁移它们,因为用户是关键依赖项。

© www.soinside.com 2019 - 2024. All rights reserved.