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