Dynamics CRM: ExecuteBatch vs ExecuteMultipleRequest

When working with CrmServiceClient (creating integration custom app to CRM), I always pass this object as IOrganizationService. But when I try to inspect the difference between interface IOrganizationService vs CrmServiceClient class (indeed CrmServiceClient is inherited from IOrganizationService). Later on, I found the ExecuteBatch method on CrmServiceClient and ended up google it and found an article from Inogic that you can access here (from 2017!). Based on the blog post, we can use ExecuteBatch to run multiple requests at the same time to CRM. So today, we will be learning what’s the differentiation between using ExecuteBatch vs ExecuteMultipleRequest.

Flow Chart ExecuteMultipleRequest vs ExecuteBatch

To make you understand deeper, I created a new entity named new_test with two string attributes(new_name and new_normalstring). Then I create a simple plugin step to throw an error if new_normalstring is set in “25”, “50”, “60”, “70”, “90”, and “100”. This plugin step I registered on Create + PreOperation mode:

Here is the setup in the plugin registration tool:

Plugin Step

ExecuteBatch

Below is the code of how we run an ExecuteBatch:

        private static void RunBatch(CrmServiceClient client)
        {
            //var batchId = new Guid("58f06806-f1b7-41de-aea9-a858f559af88");
            var batchId = client.CreateBatchOperationRequest(batchName: $"testing-{Guid.NewGuid()}", returnResults: false, continueOnError: true);

            for (int i = 0; i < 100; i++)
            {
                var record = new new_test
                {
                    new_Name = $"Batch-{batchId}-{i}",
                    new_normalstring = i.ToString()
                };

                client.CreateNewRecord(new_test.EntityLogicalName, record.ToDictionary(), batchId: batchId);
            }

            var result = client.GetBatchById(batchId);

            Console.WriteLine($"{result.BatchName}: {result.BatchItems.Count}..");


            var data = client.ExecuteBatch(batchId);

            foreach (var response in data.Responses)
            {
                Console.WriteLine($"{response.RequestIndex}: {response.Fault}..");
            }
        }
    }

As you can see from the above code, one of the things that I don’t really like is we need to pass Dictionary<string, CrmDataTypeWrapper> which is not a common data type that we use a lot when developing CRM. So to suit my preference, I created the below extension to convert Entity to become Dictionary<string, CrmDataTypwWrapper> that can solve Create scenario:

    public static class EntityExtensions
    {
        public static Dictionary<string, CrmDataTypeWrapper> ToDictionary(this Entity entity)
        {
            if (entity == null) throw new ArgumentNullException(nameof(entity));

            var result = new Dictionary<string, CrmDataTypeWrapper>();
            foreach (var item in entity.Attributes)
            {
                result[item.Key] = new CrmDataTypeWrapper(item.Value, CrmFieldType.Raw);
            }

            return result;
        }
    }

And here is the result of the above code:

Result

For testing how the ExecuteBatch run, I do the below testing:

Testing running without ExecuteBatch

I executed the creation of several records but did not call ExecuteBatch. Then I copy the batchId, stop the program, then run again with the below code:

Running previously batchId, will throw an error

Meaning it proves that it will only store all the transactions in our computer memory. Only when we call ExecuteBatch, it will push to CRM.

ExecuteMultipleRequest

Below is the code of how we run an ExecuteMultipleRequest:

        private static void RunManualBatch(CrmServiceClient client)
        {
            var multipleRequest = new ExecuteMultipleRequest
            {
                Settings = new ExecuteMultipleSettings { ContinueOnError = true, ReturnResponses = false },
                Requests = new OrganizationRequestCollection()
            };

            for (int i = 0; i < 100; i++)
            {
                var record = new new_test
                {
                    new_Name = $"Batch-manual-{i}",
                    new_normalstring = i.ToString()
                };

                multipleRequest.Requests.Add(new CreateRequest { Target = record });
            }

            var data = (ExecuteMultipleResponse)client.Execute(multipleRequest);

            foreach (var response in data.Responses)
            {
                Console.WriteLine($"{response.RequestIndex}: {response.Fault}..");
            }
        }

This implementation is cleaner in my opinion and will produce the same result as the above code (ExecuteBatch).

Summary

Even I do choose the ExecuteMultipleRequest way (because it is simpler+cleaner for me). But there is a scenario where the ExecuteBatch might be easier to be used. For example in the below picture, you can see ExecuteBatch provides the solutionId parameter that can help us to bind the created record directly.

CreateNewRecord has more functions!

So, like always: happy crm-ing!

3 thoughts on “Dynamics CRM: ExecuteBatch vs ExecuteMultipleRequest

  1. Great post. I’m curious what are the speed differences on large data runs? How does each behave with API throttling limits?

    Like

    1. I only know that CRM limited it’s API call to 60k per 5 mins (thhttps://docs.microsoft.com/en-us/powerapps/developer/data-platform/api-limits). From Azure side, we always can scale up using the higher service tier. As long as CRM able to do calling to the service bus, then no problem already (depends how we design from Azure Service Bus to the other source systems). 🙏

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.