In your Microsoft Dynamics CRM environment, data changes could happen to the same record simultaneously due to the operations initiated by different system users or applications at the same time. Such concurrency situation could sometimes result in data loss. With the introduction of Optimistic Concurrency feature in CRM Online 2015 Update 1 release, we now have a way to detect whether the record has been changed since the last time it was retrieved, which can help mitigate such potential data loss.
The Optimistic Concurrency feature is made possible by the ConcurrencyBehavior option of UpdateRequest and DeleteRequest message.
The following snippet shows how the behavior is used in the scenario when you need to perform an update of CRM record.
using (var service = new OrganizationService(crmConnection)) { var account = service.Retrieve("account", accountId, new ColumnSet("name", "revenue", "creditlimit")); // Here you might be doing something that takes a lot time in which case that the CRM record could be modified by other application or system user. object revenue; if (account != null && account.Attributes.TryGetValue("revenue", out revenue) && ((Money)revenue).Value > 50000000) { var updatedAccount = new Entity() { LogicalName = account.LogicalName, Id = account.Id, RowVersion = account.RowVersion }; updatedAccount["creditlimit"] = new Money(5000); // Define the update behavior so it only happens when RowVersion matches var accountUpdate = new UpdateRequest() { Target = updatedAccount, ConcurrencyBehavior = ConcurrencyBehavior.IfRowVersionMatches }; // Make update service call try { var accountUpdateResponse = (UpdateResponse)service.Execute(accountUpdate); } catch (FaultException<OrganizationServiceFault> ex) { if (ex.Code == OPTIMISTIC_CONCURRENCY_VIOLATION) { // TODO: Handle the exception } } } }
ConcurrencyBehavior option is also available for DeleteRequest message, which provides a similar logic. Delete will fail if the record has been changed by another thread since it was retrieved. The following snippet demonstrates the code pattern that you can use.
using (var service = new OrganizationService(crmConnection)) { var account = service.Retrieve("account", accountId, new ColumnSet("name", "revenue", "creditlimit")); // Here you might be doing something that takes a lot time in which case that the CRM record could be modified by other application or system user. var accountToDelete = new EntityReference() { LogicalName = account.LogicalName, Id = account.Id, RowVersion = account.RowVersion }; var accountDelete = new DeleteRequest() { Target = accountToDelete, ConcurrencyBehavior = ConcurrencyBehavior.IfRowVersionMatches }; try { var accountDeleteResponse = service.Execute<DeleteResponse>(accountDelete); } catch (FaultException<OrganizationServiceFault> ex) { if (ex.Code == OPTIMISTIC_CONCURRENCY_VIOLATION) { // TODO: Handle the exception } } }
For more details about this feature, please check out CRM SDK online documentation page: Reduce potential data loss using optimistic concurrency.
Hope this has helped.
Cheers,
Daniel Cai | KingswaySoft
Read the full New SDK Capabilities Blog Series:
- Part 1 - Alternate Keys
- Part 2 - Upsert
- Part 3 - No more special messages for special fields
- Part 4 - Plugin Trace Logging
- Part 5 - Entity Change Tracking
- Part 6 - Transactional Batching
- Part 7 - Optimistic Concurrency
- Part 8 - New Query Operators
- Part 9 - Detect SDK Capabilities by Checking CRM Server Version