Data Access has been discontinued. Please refer to this page for more information.

Managing Concurrency

By default, Telerik Data Access implements an optimistic concurrency control. This means that locks are not held on data in the data store between the data is queried and the data is updated. Telerik Data Access checks for changes in the database before saving changes to the database. Any conflicts will cause an Telerik.OpenAccess.Exceptions.OptimisticVerificationException. The way you handle concurrency exceptions depends on the business rules required by your application. When making updates in such high concurrency scenarios, you could use the Refresh method frequently. After Refresh is called, the object’s original values will always be updated with the data source value, but the current values might or might not be updated with the data source value. This depends on the RefreshMode value, it controls how changes are propagated. The OverwriteChangesFromStore value means that the passed object should be updated to match the data source values. The PreserveChanges value means that the actual changes in the object will be kept but all clean data will be re-read. When an OptimisticVerificationException occurs, you could handle it by calling Refresh, and specifying whether the conflict should be resolved by preserving data in the object or by updating the object with the data from the data store, as in the following example.

In this example, changes to the Product object cause an OptimisticVerificationException. The concurrency conflict is resolved by refreshing the object, making the changes again and re-saving it.

using (FluentModel dbContext = new FluentModel())
{
   Product product = dbContext.Products.FirstOrDefault();
   try
   {
       product.Name = product.Name + "-";
       dbContext.SaveChanges();
   }
   catch (Telerik.OpenAccess.Exceptions.OptimisticVerificationException ex)
   {
       dbContext.Refresh(Telerik.OpenAccess.RefreshMode.OverwriteChangesFromStore, product);
       product.Name = product.Name + "-";
       dbContext.SaveChanges();
   }
}
Using dbContext As New FluentModel()
 Dim _product As Product = dbContext.Products.FirstOrDefault()
 Try
  _product.Name = _product.Name & "-"
  dbContext.SaveChanges()
 Catch ex As Telerik.OpenAccess.Exceptions.OptimisticVerificationException
  dbContext.Refresh(Telerik.OpenAccess.RefreshMode.OverwriteChangesFromStore, _product)
  _product.Name = _product.Name & "-"
  dbContext.SaveChanges()
 End Try
End Using

The OpenAccessContext exposes a method named GetLastConflicts, which allows you to get the ObjectKeys for all failing object.

using (FluentModel dbContext = new FluentModel())
{
   Product product = dbContext.Products.FirstOrDefault();
   try
   {
       product.Name = product.Name + "-";
       dbContext.SaveChanges();
   }
   catch (Telerik.OpenAccess.Exceptions.OptimisticVerificationException ex)
   {

       IList<ConcurrencyConflict> conflicts = dbContext.GetLastConflicts();

       dbContext.Refresh(Telerik.OpenAccess.RefreshMode.OverwriteChangesFromStore, product);
       product.Name = product.Name + "-";
       dbContext.SaveChanges();
   }
}
Using dbContext As New FluentModel()
 Dim _product As Product = dbContext.Products.FirstOrDefault()
 Try
  _product.Name = _product.Name & "-"
  dbContext.SaveChanges()
 Catch ex As Telerik.OpenAccess.Exceptions.OptimisticVerificationException

  Dim conflicts As IList(Of ConcurrencyConflict) = dbContext.GetLastConflicts()

  dbContext.Refresh(Telerik.OpenAccess.RefreshMode.OverwriteChangesFromStore, _product)
  _product.Name = _product.Name & "-"
  dbContext.SaveChanges()
 End Try
End Using

By default the GetLastConflicts method will return only the first conflict because calculating the rest takes too much time. However, if you want to get all conflicts, you can pass the ConcurrencyConflictsProcessingMode.AggregateAll enumeration value in the SaveChanges method. The AggregateAll option executes all insert, update and delete statements regardless of an error. If all failures during commit should be collected and not only the first one, then the AggregateAll mode should be used. This can be a time consuming operation. The other possible value is StopOnFirst, which will stop the processing after the first error.

Collecting all failures during commit can be a time consuming operation.

dbContext.SaveChanges(ConcurrencyConflictsProcessingMode.AggregateAll);
dbContext.SaveChanges(ConcurrencyConflictsProcessingMode.AggregateAll)