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 resources 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 the 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 the Execute method, wherein we need to execute each of the requests separately, consuming more of the resources and definitely adding a burden to the Organisation's Service of the system.
Overhead with ExecuteMultipleRequest, it accepts an input collection of message requests, executes each of the message requests sequentially as they have been added to 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 organizationService.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 an iterator to get an Entity from this collection.
- Using the Execute method to take up the CREATE action individually for each record.
- If a record is created successfully, it's fine; otherwise, 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 for the custom entity?
Resolution
ExecuteMultiple has run-time execution options through which we can define what should happen if certain records fail or decide if we need the response or not for the action undertaken through ExecuteMultiple,
Execute Multiple members Setting |
Description |
Continue On Error |
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. |
Return Responses |
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.
function sampleExecuteMultiple(IOrganisationService _service) {
#
region Execute Multiple with Results
// Creating an object for ExecuteMultipleRequest
ExecuteMultipleRequest requestWithResults = new ExecuteMultipleRequest() {
// Setting the values for ContinueOnError and ReturnResponses during the execution of request
requestSettings = new ExecuteMultipleSettings() {
ContinueOnError = false,
ReturnResponses = true
},
// Create an empty organization request collection.
Requests = new OrganizationRequestCollection()
};
// Will be loading this collection with the data from Excel File
For reference will be adding the
function
for GetCollectionOfEntitiesToCreate
EntityCollection input = GetCollectionOfEntitiesToCreate();
// undertaking the operation of creating requests
foreach(var entity in input.Entities) {
CreateRequest createRequest = new CreateRequest {
Target = entity
};
requestWithResults.Requests.Add(createRequest);
}
// Execute all the requests in the request collection using a single web method call.
ExecuteMultipleResponse responseWithResults = (ExecuteMultipleResponse) _service.Execute(requestWithResults);
}
Code
for capturing the response(
if set to TRUE in settings): -
// Display the results returned in the responses.
foreach(var responseItem in responseWithResults.Responses) {
// A valid response.
if (responseItem.Response != null) DisplayResponse(requestWithResults.Requests[responseItem.RequestIndex], responseItem.Response);
// An error has occurred.
else if (responseItem.Fault != null) DisplayFault(requestWithResults.Requests[responseItem.RequestIndex], responseItem.RequestIndex, responseItem.Fault);
// In my case since I needed the response with values for failed record to create a request in custom entity
Entity x1 = input.Entities.ElementAt(responseItem.RequestIndex);
// Exactly responseItem.RequestIndex gives us the Index value of the Entity Record in the input collection
// Lets say custom entity is XYZ
Entity v1 = new Entity(“XYZ”);
V1[“description”] = x1.GetAttributeValue < string > (“description”);
// Again if needed we can create a collection of all the error records and can create the records through ExecuteMultiple request
}
Sample Code
for GetCollectionOfEntitiesToCreate: -Private EntityCollection GetCollectionOfEntitiesToCreate() {
EntityCollection x1 = new EntityCollection();
For(int i = 0; i < 1000; i++) {
Entity a1 = new Entity(“Contact”);
a1.[“name”] = ”Sample”;
// adding values to the EntityCollection
X1.Entities.Add(a1);
}
return x1;
}
Limitations
Everything comes 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 minutes to complete the same process.
Regarding Sample Code
The 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.