As a developer, you always want to perform any database operation in a Transaction so that you have the choice of rollback in case an operation fails. There are many examples where you want either all of your API instructions to succeed or all of them to rollback. If there is only a partial successful execution, it could lead the database in an unstable state. This is especially true of scenarios where you would like to create one record with multiple other related records. You want the master record created only if all other related records could be successfully created as well. If any related operation fails, do not create the master record as well.
Unfortunately, until this update, Dynamics CRM did not support transaction for actions performed through the API by the developers.
This is a new request that is introduced with the Dynamics CRM Online Update 1 (7.1.x). With this request you need to provide a collection of Organization request like Create, Update, Delete, SetState, Assign, any organization request and have CRM execute them in a transaction. This means any of the request in the collection fails, all the other requests would also rollback. The response of this request would also be a collection of responses corresponding to every request that was included in the request collection.
ExecuteTransactionRequest execTrans = new ExecuteTransactionRequest()
ReturnResponses = true,
Requests = new OrganizationRequestCollection()
Below is an example of how could you add different organization requests in the request collection. Note, we are adding different messages for the sake of clarity about this message.
///// Create Account Request//////
Entity account = new Entity(“account”);
account[“name”] = “Transaction request 1”;
CreateRequest createAcc = new CreateRequest();
createAcc.Target = account;
//add create request in a request collection
////// Update request ///////
Entity contact1 = new Entity(“contact”);
contact1[“firstname”] = “Samantha”;
contact1[“lastname”] = “Ray”;
contact1[“emailaddress1”] = “firstname.lastname@example.org”;
//set gender value
contact1[“gendercode”] = new OptionSetValue(3);
//Update request to update a contact
UpdateRequest upReq = new UpdateRequest();
upReq.Target = contact1;
upReq.Target.Id = new Guid(“58C7D2CB-7A0E-E511-80DC-FC15B4289E14”);
//add update request in a collection
///// Status Change Request //////
SetStateRequest state = new SetStateRequest();
//set the reference of target entity
state.EntityMoniker = new EntityReference(“contact”, new Guid(“A925C42D-CFE4-E411-80E8-C4346BAD5414”));
//set the state of the record to inactive
state.State = new OptionSetValue(1);
state.Status = new OptionSetValue(2);
//add set state request in collection
///// Delete request //////
DeleteRequest delete = new DeleteRequest();
//provide target entity reference which needs to be deleted
delete.Target = new EntityReference(“account”, new Guid(“4125C42D-CFE4-E411-80E8-C4346BAD5414”));
//add delete request in collection
Finally execute the ExcecuteTransaction Request
//Execute the request
ExecuteTransactionResponse response = (ExecuteTransactionResponse)_service.Execute(execTrans);
The response of this can be read as shown below
response.Responses would contain the collection of the responses returned for each of the request submitted to the request above.
You can read the response for each of the individual request by matching the index in the request collection with that in the response collection.
For the create request, the response would provide the id in the response.
OrganizationResponse resp = response.Responses
Since this was a createRequest, the response would be the CreateResponse that is returned. You can find the Guid of the newly created record
id = (Guid)orgResponse.Results[“id”];
If an error occurs in executing any of the message in the collection, it would throw a fault exception of the type ExecuteTransactionFault which will return the index of a request collection of the request message that caused the fault.
Here is how it looks in the debugger
You can read it using the following code.
catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> ex)
ExecuteTransactionFault fault = (ExecuteTransactionFault)ex.Detail;
int faultedIndex = fault.FaultedRequestIndex;
Do not confuse this with ExecuteMultiple that was introduced in one of the earlier updates to Dynamics CRM. Some points to remember
- ExecuteMultiple allowed you to process multiple messages in a single batch to reduce the roundtrips required to process multiple messages.
- ExecuteTransaction goes a step further to ensure that all of the messages submitted to it are executed in Transaction mode. Rollback if any message fails.
- You can include an ExecuteMultiple request within an ExecuteTransaction request.
- The max messages that can be executed in a batch is 1000
Hope it helps!
There’s much more. For any assistance in implementation, customization, migration or upgradation of Dynamics CRM, get in touch with us on email@example.com.