In this article we will touch base some important concepts of handling concurrency in LINQ to SQL. We will first see how LINQ supports optimistic concurrency and then we will see what support LINQ provides to handle concurrency violation. We will then touch base on some fine tuning features provided by LINQ at field level and finally we will end this article by discussing two important error reporting options when concurrency conflict happens.
How to handle concurrency in LINQ to SQL?
Introduction and Goal
Still new to LINQ below are some real quick starters
2 things a good concurrency system should support
LINQ supports optimistic concurrency by default
Let’s see if really optimistic concurrency works
3 ways of handling concurrency violation in LINQ
Fine tuning concurrency at field level
Error reporting options during concurrency conflicts
Source code
In this article we will touch base some important concepts of handling concurrency in LINQ to SQL. We will first see how LINQ supports optimistic concurrency and then we will see what support LINQ provides to handle concurrency violation. We will then touch base on some fine tuning features provided by LINQ at field level and finally we will end this article by discussing two important error reporting options when concurrency conflict happens.
Please feel free to download by free .NET Ebook which has 400 questions and answers in WCF,WPF,WWF,Silverlight and lot more
http://www.questpond.com/SampleDotNetInterviewQuestionBook.zip
Are you a complete newbie :- http://www.dotnetfunda.com/articles/article278.aspx
Want to define 1-* and *-1 using LINQ :- http://www.dotnetfunda.com/articles/article446-onemany-and-oneone-relationship-using-linq-to-sql.aspx
Issues of multiple trips handled in this article :- http://www.dotnetfunda.com/articles/article455-optimizing-linq-queries-using-dataloadoptions.aspx
Do not know how to call stored procedures using LINQ :- http://www.dotnetfunda.com/articles/article458-simple-6-steps-to-use-stored-procedure-in-linq.aspx
A good concurrency system should at least provide two important features:-
• It should be able to detect if any concurrency violation has taken place.
• Once concurrency violation has been detected it should provide various ways of how to handle the concurrency violation.
LINQ entity forms the main heart of LINQ engine. All the data from database is fetched using ‘datacontext’ and given to LINQ objects. Once the data is fetched in the LINQ objects the LINQ objects gets disconnected from the database, in other words LINQ is a disconnected architecture. Due to disconnected architecture the only type of locking we can support is optimistic locking.
Good news !!! LINQ supports optimistic concurrency by default.
Let’s do a small sample test to see that does LINQ really support optimistic concurrency default. So we will do the following:-
• We will open a data context, fetch a record and modify the record. We will not be calling ‘SubmitChanges’ , in other words we will not be making final update to physical database.
• We will then open a new ‘DataContext’ connection, fetch the same record and update the record physically in the database.
• Then we will come back to the same old record to call the physical update using ‘SubmitChanges’. In this way we will be able to simulate concurrency violation.
So below goes the code.
We first fetch the record and change the customer name but we have not called the physical database commit yet.
DataContext objContext = new DataContext(strConnectionString);
clsCustomer objCustomer = objContext.GetTable<clsCustomer>().First<clsCustomer>();
objCustomer.CustomerName = "Iwanttochange";
We then call a different method which will change this record by which we can simulate concurrency simulation.
SomeOneChangedData();
The ‘SomeOneChangedData’ method is a simple code which fetches the same record and changes it.
private void SomeOneChangedData()
{
DataContext objContext = new DataContext(strConnectionString);
clsCustomer objCustomer = objContext.GetTable<clsCustomer>().First<clsCustomer>();
// changing to some random customer name
objCustomer.CustomerName = new Random().NextDouble().ToString();
objContext.SubmitChanges();
}
We then come back to the old ‘DataContext’ object and try to call the ‘SubmitChanges’ method. This call will create concurrency violation as ‘SomeOneChangedData’ method has already changed data.
objContext.SubmitChanges();
If you are in debug mode you should see ‘ChangeConflictException’ exception thrown as shown in the below figure.
If you want to really see the exception you can run the code without try and catch exception block. You should see something as shown in the below figure.
3 ways of handling concurrency violation in LINQ
When we started this article we talked about the two important features which every good concurrency system should have. We have already seen the live demonstration of the first feature which showed how LINQ helps to detect concurrency conflicts. Now let’s see how LINQ satisfies the second feature for concurrency which is handling concurrency conflicts.
LINQ gives three ways by which we can handle concurrency conflicts. To handle concurrency conflicts we need to wrap the LINQ to SQL code in a ‘TRY’ block and catch the ‘ChangeConflictException’. We can then loop through the ‘ChangeConflicts’ collection to specify how we want the conflict to be resolved.
catch (ChangeConflictException ex)
{
foreach (ObjectChangeConflict objchangeconf in objContext.ChangeConflicts)
{
objchangeconf.Resolve(RefreshMode.OverwriteCurrentValues);
}
}
There are 3 ways provided by LINQ system to handle concurrency conflicts:-
• KeepCurrentValues :- When this option is specified and concurrency conflicts happen LINQ keeps call the LINQ entity object values as it is and does not push the new values from the database in to the LINQ object.
• OverwriteCurrentValues :- When this option is specified the current LINQ object data is replaced with the database values.
• KeepChanges :- This is the most weird option but can be helpful in some cases. When we talk about classes it can have many properties. So properties which are changed are kept as it is but the properties which are not changed are fetched from the database and replaced.
We need to use the ‘RefereshMode’ to specify which options we need as shown in the below code snippet.
One of the best options provided by LINQ concurrency system is control of concurrency behavior at field level. There are three options we can specify using the ‘UpdateCheck’ attribute:-
• Never: - Do not use this field while checking concurrency conflicts.
• Always: - This option specifies that always use this field to check concurrency conflicts.
• WhenChanged :- Only when the member value has changed then use this field to detect concurrency conflicts.
Below is the code snippet which show how we can use the ‘UpdateCheck’ attribute to control property / field level concurrency options as specified above.
[Column(DbType = "nvarchar(50)",UpdateCheck=UpdateCheck.Never)]
public string CustomerCode
{
set
{
_CustomerCode = value;
}
get
{
return _CustomerCode;
}
}
LINQ concurrency system lets you specify how you want the conflicts to be reported. LINQ system has given 2 ways to report conflicts:-
ContinueOnConflict :- This option says to the LINQ engine that continue even if there are conflicts and finally return all conflicts at the end of the process.
FailOnFirstConflict :- This option says stop as soon as the first conflict occurs and return all the conflicts at that moment. In other words LINQ engine does not continue ahead executing the code.
Both these options can be provided as a input in ‘SubmitChanges’ method using the ‘ConflictMode’ enum. Below is the code snippet of how to specify conflict modes.
objContext.SubmitChanges(ConflictMode.ContinueOnConflict);
You can get the source code attached with this article.