Concurrency Control with OpenAccessLinqDataSource
Operations on persistent classes in a database are always performed in the context of a transaction. A transaction is an ordered sequence of operations that transforms a database from one state of consistency to another state of consistency. The data in Telerik Data Access database is maintained in a transactional consistent state according to the standard definition of ACID transactions. Telerik Data Access assures that changes to the values of persistent instances are consistent with changes to other values in the same instance. Telerik Data Access supports several different approaches for optimistic concurrency control - using Timestamp column, DateTime column, Version Number or Checking for any changes. For more information, refer to the Optimistic Concurrency Control topic.
In this topic, you will learn how to check for data conflicts when you update data by using an OpenAccessLinqDataSource control. It will be demonstrated how to use a Timestamp column with the OpenAccessLinqDataSource control for concurrency control. The simplest mechanism for detecting that anything in a database row has changed is to use a timestamp (also known as rowversion) field. A timestamp is a binary field that is automatically updated whenever changes are made to any columns in the row. Many databases have a specific data type that is used for this. SQL Server uses the timestamp data type. The OpenAccessLinqDataSource control stores the timestamp value in the view state. When the user updates data, the OpenAccessLinqDataSource control checks the timestamp value against the current timestamp value in the database. If the data source control detects that the value in the timestamp column has changed, the control does not update the record. Instead, a new OptimisticVerificationException will be thrown.
Configuring an OpenAccessLinqDataSource to Use Timestamp Column for Concurrency Control
This section shows you how to configure an OpenAccessLinqDataSource control to use a Timestamp column for concurrency control.
The example in this article consumes a fluent model project created with the steps described in the Creating The SofiaCarRental Model tutorial.
-
The first step is to create a new column in the Categories database table with Data Type *timestamp*.
-
Open the Category.cs(vb) class and add a new field and a new property for the Timestamp column.
public partial class Category { //The code for the rest of the fields and properties private long _timestamp; public virtual long Timestamp { get { return this._timestamp; } set { this._timestamp = value; } } }
Public Partial Class Category ' The code for the rest of the fields and properties Private _timestamp As Long Public Overridable Property Timestamp As Long Get Return Me._timestamp End Get Set(ByVal value As Long) Me._timestamp = value End Set End Property End Class
-
Open the FluentModelMetadataSource.cs(vb) file and change the concurrency control strategy of the Category class to Backend:
configuration.MapType(x => new { }). WithConcurencyControl(OptimisticConcurrencyControlStrategy.Backend). ToTable("Categories");
configuration.MapType(Function(x) New With {x}). WithConcurencyControl(OptimisticConcurrencyControlStrategy.Backend). ToTable("Categories")
-
Add a new property configuration for the timestamp column. Make sure to set it as version through the IsVersion method:
configuration.HasProperty(x => x.Timestamp).HasFieldName("_timestamp"). IsVersion().WithDataAccessKind(DataAccessKind.ReadWrite). ToColumn("Timestamp").IsNotNullable().HasColumnType("timestamp"). HasPrecision(0).HasScale(0);
configuration.HasProperty(x => x.Timestamp).HasFieldName("_timestamp"). IsVersion().WithDataAccessKind(DataAccessKind.ReadWrite). ToColumn("Timestamp").IsNotNullable().HasColumnType("timestamp"). HasPrecision(0).HasScale(0)
Rebuild the fluent model project.
-
Configure your OpenAccessLinqDataSource control to use the table with the Timestamp column.
<telerik:OpenAccessLinqDataSource ID="OpenAccessLinqDataSourceCategory" runat="server" ContextTypeName="SofiaCarRental.Model.FluentModel" ResourceSetName="Categories"> </telerik:OpenAccessLinqDataSource>
-
Enable the OpenAccessLinqDataSource control to perform automatic inserts and updates.
<telerik:OpenAccessLinqDataSource ID="OpenAccessLinqDataSourceCategory" runat="server" EnableInsert="True" EnableUpdate="True" ContextTypeName="SofiaCarRental.Model.FluentModel" ResourceSetName="Categories"> </telerik:OpenAccessLinqDataSource>
Connect the OpenAccessLinqDataSource control to a data-bound control, for example: RadGrid.
Testing the Concurrency Control
To see how the timestamp column prevents updates when the data has changed, you could perform the following test:
- Run your page in the browser.
- Select a record and then click the Edit link (button). Make some modifications, but do not update the record yet.
- In Visual Studio, open the Server Explorer pane. Right-click the underlying table and click Show Table Data.
- Change a value in the same record that you opened in the Web browser. Press Enter to write the change to the database. The timestamp column for the records is updated automatically.
- Go back to your page in the Web browser and update the record by clicking the Update link.
- You should receive an exception saying "Concurrent update detected".
Handling an OptimisticVerificationException Exception
If you want to perform an action when an OptimisticVerificationException is thrown, you need to handle the Updating event of the OpenAccessLinqDataSource control.
How to Enable/Disable Concurrency Control
The OpenAccessLinqDataSource control exposes the StoreOriginalValuesInViewState property. It specifies whether to store original data values in ViewState or not. This property is used for conflict detection. The default value for the StoreOriginalValuesInViewState property is True, which means that the concurrency control is enabled by default. To disable the concurrency control, you need to set the StoreOriginalValuesInViewState property of the OpenAccessLinqDataSource control to False.