Monday, February 11, 2013

A Potent Cocktail: ExecuteMultiple and LINQ

I love it when technologies using the same framework marry together like peaches and cream.  Today, I want to cover the intersection of CRM 2011’s new ExecuteMultiple capabilities and my love of LINQ.  Just to be clear, I’m not talking about using LINQ provider for CRM, though you can certainly use that to produce a collection of records upon which to perform some operation in bulk.

Instead, I’d like to show you an elegant snippet of code that demonstrates the power of ExecuteMultiple with the cleanliness of succinct LINQ.  Given an EntityCollection —someRecords— suppose that you need to increment some integer —my_integer— on each of the contained records.  For the purposes of this example, I’ll be using the late-bound Entity type.

// Start our request with some basic initialization
ExecuteMultipleRequest bulkIncrementRequest = new ExecuteMultipleRequest()
    Settings = new ExecuteMultipleSettings()
        ContinueOnError = true,
        ReturnResponses = true
    Requests = new OrganizationRequestCollection()

// Compile the collection of requests
bulkIncrementRequest.Requests.AddRange( from record in someRecords.Entities
                                        where record.Contains( "my_integer" )
                                        select new UpdateRequest() 
                                            Entity = new Entity( "someRecord" )
                                                Id = record.Id,
                                                Attributes = {
                                                    new KeyValuePair( "my_integer",
                                                        ( ( Int32 ) record[ "my_integer" ] ) + 1 )
                                        } );

// Excute the requests
ExecuteMultipleResponse bulkIncrementResponse = ( ExecuteMultipleResponse ) service.Execute( bulkIncrementRequest );

// Check "IsFaulted" to determine if any of the submitted requests failed
if ( bulkIncrementResponse.IsFaulted )
    Int32 errorCount = ( from incrementResponse in bulkIncrementResponse.Responses
                         where incrementResponse.Fault != null
                         select incrementResponse ).Count();

By using LINQ to inject the AddRange method of Requests, I was able to compound the code that loops through each record, selects the original value, increments it, and produces a request to update the record. 

Keen observers notice that I created a new Entity object from the old one; this is a best-practice to avoid triggering updates on attributes undesirably.  However, it also allows me to perform the increment operation inline.  I’m sure you could inject this operation into a secondary where statement, but I think that makes the query logic less readable.  But your mileage may vary.  :)