Search code examples
c#.netdynamics-crm-2011dynamics-crm-2016

Updating a field through workflows, better approach?


I have been asked to create a view that includes entities that fit within a date range. So if the entity's new_date1 field is lesser than today, and its new_date2 field is greater than today, the entity should appear in the subgrid on the form.

Unfortunately, you can't do this with simple views as FetchXML doesn't support calculations and operators that could return today's date.

I have come up with the idea of creating an Active field on the entity, then have javascript rules set that field depending on the date range entered.

A view could then use the Active field for a filter criteria.

The problem is that if the entity's form is not opened in a while, the entity might become inactive (today's date is now beyond both date1 and date2 for example) but if the users are not opening the entity's form, the field won't update itself and the view will show inactive entities as active ones.

So I thought of have a scheduled workflow gather all entities that should be active, or inactive then this workflow launches a child workflows, that either sets the Active flag to yes or no.

Here's a bit of the code involved:

private void LaunchUpdateOpportunityWorkflow(IOrganizationService service, ITracingService tracingService, DataCollection<Entity> collection, bool active)
{

        foreach (Entity entity in collection)
        {
            //launch a different workflow, depending on whether we want it active or inactive...
            Guid wfId = (active) ? setActiveWorkflowId : setInactiveWorkflowId;
            ExecuteWorkflowRequest execRequest = new ExecuteWorkflowRequest();
            execRequest.WorkflowId = wfId;
            execRequest.EntityId = (Guid)entity["opportunityid"];

            try
            {
                CrmServiceExtensions.ExecuteWithRetry<ExecuteWorkflowResponse>(service, execRequest);
            }
            catch (Exception ex)
            {
                tracingService.Trace(string.Format("Error executing workflow for opportunity {0}: {1}", entity["opportunityid"], ex.Message));
            }
        }

}

The process of gathering the relevant DataCollection is done through simple RetrieveMultipleRequest requests.

The problem with that approach is that if the server reboots, someone has to go and start the workflow that runs the code above.

Is there better a approach to this ? I am using MS CRM 2016.


Solution

  • Adding to Jame's answer, if the filter criterias get complicated where it cannot be achieved using fetchxml, you can always use a plugin.

    Register a plugin on "RetrieveMultiple" message.

    var queryExpression = PluginExecutionContext.InputParameters["Query"];
    if(queryExpression == null || !queryExpression.EntityName.equals("yourentityname", StringComparison.InvariantCultureIgnoreCase) return;
    

    Add a condition which is unique to the advanced find, because there is no way to filter down on which advanced find is triggering the plugin on your entity, easiest way to achieve this would be to add an attribute and use it in the advanced find query.

    Check for the condition, if found, the user is trying to run the advanced find you have set up:

    if (queryExpression.Criteria == null || queryExpression.Criteria.Conditions == null ||
    !queryExpression.Criteria.Conditions.Any()) return;
    

    Find the matching condition, so you can remove it and add conditions you'd like to filter the data by:

     var matchContidion = queryExpression.Criteria.Conditions.FirstOrDefault(c => c.AttributeName == "yourflagattribute");
     if (matchContidion == null) return;
    

    Remove the dummy match criteria and add your own criterias:

    queryExpression.Criteria.Conditions.Remove(matchContidion);
    queryExpression.Criteria.Conditions.Add(new ConditionExpression("new_date1", ConditionOperator.LessThan, DateTime.Now));
    queryExpression.Criteria.Conditions.Add(new ConditionExpression("new_field2", ConditionOperator.Equals, "Some complex value which cannot be set using fetchxml")); //for example, based on certain values, you might want to call a webservice to get the filter value.