Dynamics 365 - Execute Multiple Requests

Sometimes, in projects, we have a requirement where we need to undertake the actions at once on numerous records in the system over an entity. In this article, we will see how to achieve that.

Overview

 
In projects, often, we do have requirements wherein we need to undertake actions at once on numerous records in the system over an entity, or we need to load data through console applications to undertake required actions in the system. The action over multiple records consumes a lot of resource going by the conventional method of using the “Execute” method, as the code executes/pushes each request separately to Dynamics CRM.

To overcome this delay, ExecuteMultiple message was introduced in Dynamics CRM to enhance the performance of the system during implementation of an action over bulk-data.

What is ExecuteMultiple?

ExecuteMultiple is a message introduced to support higher throughput bulk message passing scenarios in Microsoft Dynamics 365 (online & on-premises), particularly in the case of Microsoft Dynamics 365 (online) where internet latency can be the largest limiting factor.

Explanation for ExecuteMultiple

Going by the orthodox method, while undertaking the action over the bulk data, we use Execute method, wherein we need to execute each of the requests separately, consuming more of the resources and definitely adding burden to the Organisation Service of the system.

Overhead with ExecuteMultipleRequest is it accepts an input collection of message Requests, executes each of the message requests sequentially as they have been added in the input collection, and based upon the settings it returns a collection of Responses containing each message’s response or the error that occurred for the requests in the collection.

Each message request in the input collection is processed in a separate database transaction. ExecuteMultipleRequest is executed by using the traditional IOrganizationService.Execute method.

Internally ExecuteMultipleRequest behaves the same as if we have executed each message request in the input request collection separately, except with better performance.

Sample Scenario for Explanation

Client requirement wherein bulk data has to be loaded to Dynamics CRM from CSV extracts on regular basis through Executables (Console Application).

  • Successfully loaded records have to be created in Contact Entity
  • Failed records need to be loaded to a custom entity for reference

Conventional Way to achieve the same

  • Using the code to read the records from the file extract shared at a specific location
  • Loading this data to a specific EntityCollection
  • Using iterator to get Entity from this collection
  • Using Execute method to take up the CREATE action individually for each record
  • If a record is created successfully, it's fine; else make an individual call to create a record in the custom entity

Using ExecuteMultiple

  • Using the code to read the records from file extract shared at a specific location
  • Loading the data to a specific EntityCollection
  • Adding each entity to the request message (In our case – CreateRequest)
  • ExecuteMultiple to execute this message in a single go

Concerns

  • What would happen if certain records in collection will fail?
  • How would I meet the requirement for creating the failed records to the custom entity?

Resolution

ExecuteMultiple has run-time execution options through which we can define what should happen if certain records fail or deciding if we need the response or not for the action been undertaken through ExecuteMultiple,
 
ExecuteMultipleSettings MemberDescription
ContinueOnError· When true, continue processing the next request in the collection even if a fault has been returned from processing the current request in the collection.· When false, do not continue processing the next request.
ReturnResponses· When true, return responses from each message request processed.· When false, do not return responses.

Code

Have implemented certain scenarios for ExecuteMultiple and for reference sharing in one from the same.

  1. function sampleExecuteMultiple(IOrganisationService _service) {  
  2.     #  
  3.     region Execute Multiple with Results  
  4.     //  Creating an object for ExecuteMultipleRequest   
  5.     ExecuteMultipleRequest requestWithResults = new ExecuteMultipleRequest() {  
  6.         // Setting the values for ContinueOnError and ReturnResponses during the execution of request  
  7.         requestSettings = new ExecuteMultipleSettings() {  
  8.                 ContinueOnError = false,  
  9.                     ReturnResponses = true  
  10.             },  
  11.             // Create an empty organization request collection.  
  12.             Requests = new OrganizationRequestCollection()  
  13.     };  
  14.     // Will be loading this collection with the data from Excel File  
  15.     For reference will be adding the  
  16.     function  
  17.     for GetCollectionOfEntitiesToCreate  
  18.     EntityCollection input = GetCollectionOfEntitiesToCreate();  
  19.     //undertaking the operation of creating requests  
  20.     foreach(var entity in input.Entities) {  
  21.         CreateRequest createRequest = new CreateRequest {  
  22.             Target = entity  
  23.         };  
  24.         requestWithResults.Requests.Add(createRequest);  
  25.     }  
  26.     // Execute all the requests in the request collection using a single web method call.  
  27.     ExecuteMultipleResponse responseWithResults = (ExecuteMultipleResponse) _service.Execute(requestWithResults);  
  28. }  
  29. Code  
  30. for capturing the response(  
  31.         if set to TRUE in settings): -  
  32.     // Display the results returned in the responses.  
  33.     foreach(var responseItem in responseWithResults.Responses) {  
  34.         // A valid response.  
  35.         if (responseItem.Response != null) DisplayResponse(requestWithResults.Requests[responseItem.RequestIndex], responseItem.Response);  
  36.         // An error has occurred.  
  37.         else if (responseItem.Fault != null) DisplayFault(requestWithResults.Requests[responseItem.RequestIndex], responseItem.RequestIndex, responseItem.Fault);  
  38.         //In my case since I needed the response with values for failed record to create a request in custom entity  
  39.         Entity x1 = input.Entities.ElementAt(responseItem.RequestIndex);  
  40.         //Exactly responseItem.RequestIndex gives us the Index value of the Entity Record in the input collection  
  41.         //Lets say custom entity is XYZ  
  42.         Entity v1 = new Entity(“XYZ”);  
  43.         V1[“description”] = x1.GetAttributeValue < string > (“description”);  
  44.         //Again if needed we can create a collection of all the error records and can create the records through ExecuteMultiple request  
  45.     }  
  46. Sample Code  
  47. for GetCollectionOfEntitiesToCreate: -Private EntityCollection GetCollectionOfEntitiesToCreate() {  
  48.     EntityCollection x1 = new EntityCollection();  
  49.     For(int i = 0; i < 1000; i++) {  
  50.         Entity a1 = new Entity(“Contact”);  
  51.         a1. [“name”] = ”Sample”;  
  52.         //adding values to the EntityCollection  
  53.         X1.Entities.Add(a1);  
  54.     }  
  55.     return x1;  
  56. }  

Limitations

Everything goes up with certain limitations and constraints. The same applies to the ExecuteMultiple Message.

  • Recursion is not allowed – that is ExecuteMultiple can not call itself
  • ExecuteMultiple can process a collection max of 1000 records at once
  • At a time concurrently two calls of ExecuteMultiple can be processed

Observation/Benefits of Implementing the same

  • Creating records through the Execute method used to take almost 12+ mins to process an extract received. As of now, it takes almost 7 mins to complete the same process.

Regarding Sample Code

Code is just for the sake of assistance. Please feel free to undertake the changes in the same as per your requirement.

Feel free to share your queries and, of course, the feedback.