I am writing a CRM plug-in. It should be triggered on "RetrieveMultiple" message for the salesorder entity, in stage 20 (pre-operation).
The problem is that I need a list of all existing salesorders in that very pre-operation stage (in order to compare the list to a remote orders list and create new orders if needed).
To get a list of all orders, the naive approach is to use service.retrieveMultiple(salesOrderQuery)
where salesOrderQuery is a QueryExpression on salesorder.
This causes of course dynamics 365 process to go into an infinite loop.
My question is: How can I "pre-retrieve" all salesorders in the pre-operation stage for a "RetrieveMultiple" message on salesorder without causing an infinite loop?
I am currently thinking that maybe I should change the event that causes my plug-in to be executed. My goal is to fetch all newly created orders from a remote system when the user loads the "orders" page. The only approach I have found so far is the register my plug-in step on the "RetrieveMultiple" message.
But how to get all existing orders then?
So far, my plug-in looks as follow:
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PSPlugins
{
public class RetrieveOrdersPlugin : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
var context = serviceProvider.GetService(typeof(IPluginExecutionContext)) as IPluginExecutionContext;
// check if pre-operation
if (context.Stage != 20)
throw new InvalidPluginExecutionException("Must run as pre-operation stage 20");
if (context.MessageName != "RetrieveMultiple")
throw new InvalidPluginExecutionException("Registered for " + context.MessageName + " only RetrieveMultiple is supported");
if (context.PrimaryEntityName != "salesorder")
throw new InvalidPluginExecutionException("Registered for " + context.PrimaryEntityName + " entity and only salesorder is supported");
var tracingService = serviceProvider.GetService(typeof(ITracingService)) as ITracingService;
var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)) as IOrganizationServiceFactory;
var service = serviceFactory.CreateOrganizationService(context.UserId) as IOrganizationService;
tracingService.Trace("Plug-in RetrieveOrders executed");
QueryExpression soQuery = new QueryExpression();
soQuery.EntityName = "salesorder";
soQuery.ColumnSet = new ColumnSet() { AllColumns = true };
soQuery.Criteria = new FilterExpression();
soQuery.Criteria.FilterOperator = LogicalOperator.And;
// The following line causes an infinite loop...
EntityCollection entities = service.RetrieveMultiple(soQuery);
}
}
}
Basically RetrieveMultiple
message will be invoked in all places like Adv find, views, lookup, service.RetrieveMultiple calls where the system is being queried for that particular entity.
Use Depth
property of context to avoid infinite loops.
if (context.Depth > 1)
return;