I have a custom workflow activity that runs on delete of a custom entity.
I need to ascertain whether the delete message is a regular delete or a cascade delete from the parent entity (Opportunity).

I have found that the parent entity exists even when there is a cascade delete.

What else could I look at to find out if the delete is a result of a cascade delete?

I need to do get this info because the custom entity is updating the parent entity on delete - it should only update when the delete is not a result of a cascade delete, otherwise an SQL error is occurring, it is probably due to the fact that the workflow is trying to update a record that is being deleted in the transaction.

EDIT

Tanguy T asked the same question here, but it was not resolved.

有帮助吗?

解决方案 3

I ended up

  • Changing the relationship to referential
  • Adding an asynchronous workflow that executed on-change of the child entities' lookup to it's parent
  • The lookup was mandatory
  • The workflow checked if the field was empty and called the below custom workflow activity if it was

This custom workflow activity deletes the current record:

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);
    }
}

This is the helper class that I wrote that gets everything I need from the CodeActivityContext.
It just saves writing the same boiler plate code for each workflow.
I can also construct an object in a console application to test the workflow locally:

/* 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();
    }
}

其他提示

I believe you can check ParentContext member of workflow context. If it is null or Message of ParentContext is not equal to Delete - this means that this is not Cascade Delete. Check this article.

Change your workflow to be a plugin, then you should be able to use Plugin Shared Variables to determine that information. Just add a Pre Event plugin to the parent entity that specifies that this is part of a parent cascade delete. Then in the child plugin, just check for that variable to exist, if it doesn't you know it's not a cascade.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top