【问题标题】:Dynamics CRM Detect if Delete Message is Cascade DeleteDynamics CRM 检测删除消息是否为级联删除
【发布时间】:2014-02-17 09:57:56
【问题描述】:

我有一个在删除自定义实体时运行的自定义工作流活动。
我需要确定删除消息是来自父实体(机会)的常规删除还是级联删除。

我发现即使有级联删除,父实体也存在。

我还能查看什么来确定删除是否是级联删除的结果?

我需要获取此信息,因为自定义实体在删除时更新父实体 - 它应该只在删除不是级联删除的结果时更新,否则会发生 SQL 错误,这可能是由于工作流正在尝试更新正在事务中删除的记录这一事实。

编辑

Tanguy T asked the same question here,但没有解决。

【问题讨论】:

    标签: dynamics-crm-2011 dynamics-crm dynamics-crm-2013


    【解决方案1】:

    我相信您可以检查工作流上下文的 ParentContext 成员。如果它为 null 或 ParentContext 的 Message 不等于 Delete - 这意味着这不是级联删除。检查this article

    【讨论】:

    • 感谢您的回答。我试了一下,发现 ParentContext 对于从父实体删除和级联删除都是空的。你能指点我其他的方向吗?
    • 在这种情况下,我建议使用异步插件而不是工作流。
    【解决方案2】:

    将您的工作流程更改为插件,然后您应该能够使用Plugin Shared Variables 来确定该信息。只需向父实体添加一个 Pre Event 插件,指定这是父级联删除的一部分。然后在子插件中,只需检查该变量是否存在,如果不存在,您就知道它不是级联。

    【讨论】:

    • 共享变量在两个方面都不存在 - 手动删除记录时(这是预期的),以及通过级联删除父级删除记录时;两个删除的父上下文也是空的。
    • 哦,等等,出于某种原因,我认为这是一个插件。因为这是一个工作流程,所以这行不通。 @Bvrce,如果您将其更改为插件而不是工作流程,则可以使用它。
    • 我能够在 IWorkflowContext 中定义一个共享变量。我认为它也不适用于插件 - Tanguy 尝试使用插件。级联删除似乎有问题。
    【解决方案3】:

    我结束了

    • 将关系更改为引用
    • 添加一个异步工作流,在更改子实体时执行对其父实体的查找
    • 查找是强制性的
    • 工作流检查该字段是否为空,如果是则调用以下自定义工作流活动

    此自定义工作流活动删除当前记录:

    public class DeleteCurrentRecord : CodeActivity
    {
        protected override void Execute(CodeActivityContext context)
        {
            if (context == null)
            {
                throw new InvalidPluginExecutionException("Workflow context error. Please retry the operation.");
            }
            using (var workflowContext = new WorkflowContext(context))
            {
                DeleteRecord(workflowContext, context);
            }
        }
        public void DeleteRecord(WorkflowContext context, CodeActivityContext activityContext)
        {
            var targetId = context.Target != null ? context.Target.Id : context.TargetReference.Id;
            var targetName = context.Target != null ? context.Target.LogicalName : context.TargetReference.LogicalName;
            context.Service.Delete(targetName, targetId);
        }
    }
    

    这是我编写的辅助类,它从 CodeActivityContext 中获取我需要的一切。
    它只是节省了为每个工作流编写相同的样板代码。
    我还可以在控制台应用程序中构造一个对象来在本地测试工作流:

    /* WorkflowContext is a helper class that I wrote that gets all the CRM services
     * and everything else from a CodeActivityContext
     * I then pass an instance of it to methods
     * I add properties to WorkflowContext as needed
     * */
    /* Contains objects that are taken from CodeActivityContext
     * */
    public class WorkflowContext : IDisposable
    {
        public IOrganizationService Service { get; private set; }
        public Entity Target { get; private set; }
        public EntityReference TargetReference { get; private set; }
        public Context Linq { get; private set; }
        public IWorkflowContext CurrentContext { get; set; }
        public string PrimaryEntityName { get; set; }
        public int Depth { get; set; }
        public WorkflowContext(CodeActivityContext activityContext)
        {
            IWorkflowContext context = activityContext.GetExtension<IWorkflowContext>();
            CurrentContext = context;
            PrimaryEntityName = context.PrimaryEntityName;
            Depth = context.Depth;
            IOrganizationServiceFactory factory = activityContext.GetExtension<IOrganizationServiceFactory>();
            if (context.InputParameters.Contains("Target")) // On demand workflows do not have target
            {
                if (context.InputParameters["Target"].GetType() == typeof(Entity))
                    Target = (Entity)context.InputParameters["Target"];
                else if (context.InputParameters["Target"].GetType() == typeof(EntityReference)) // delete and some other operations are EntityReference
                    TargetReference = (EntityReference)context.InputParameters["Target"];
            }
            Service = factory.CreateOrganizationService(context.InitiatingUserId);
            Linq = new Context(Service);
        }
        // Constructor for testing
        public WorkflowContext(IOrganizationService service, Context linq, EntityReference targetReference, Entity target, bool inTransaction)
        {
            this.Service = service;
            this.Linq = linq;
            this.TargetReference = targetReference;
            this.Target = target;
        }
        public void Dispose()
        {
            Linq.Dispose();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-04-11
      • 2022-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-27
      • 1970-01-01
      相关资源
      最近更新 更多