Resolving Concurrency Conflicts in LINQ



While performing database operations, one major thing that needs to be done is Concurrency Conflicts. A concurrency conflict can happen when two sources try to modify a database at the same time.

Let us understand conflict in LINQ with an example.

ConfLinq1.gif

From the diagram above you can infer that, essentially there are three steps involved in concurrency conflict.

Step 1:

LINQ fetches data from the database when the database is in the state "A".

Step 2:

While LINQ is manipulating the data in the DataContext, the database has been modified by some other part that changed it's state to "B".

Step 3:

LINQ is trying to update the data in the database in state "B".

Now there are two ways LINQ can resolve this:

  1. Override database changes
  2. Ignore changes made by LINQ itself.

By default, LINQ DataContext supports optimistic concurrency.

The very first thing to do to resolve a concurrency conflict is to determine the table columns involved in the conflict. You can put a check flag on the entity column.

ConfLinq2.gif

When you create an entity class in LINQ to SQL, you can attribute a column with UpdateCheck as shown above. Any column attributed with UpdateCheck would be checked for optimistic concurrency.

UpdateCheck is an enum with three values.

ConfLinq3.gif

As it is very obvious that:


Never - Column value would never be checked for detecting conflict

Always- Column value would always be checked for conflict
WhenChanged - Column value would only be checked for conflict when value of column is changed.

If you set the attribute of all the columns for update check then obviously performance would be degraded.

Another option you have is as follows:
  1. Put the code updating in try catch block
  2. Check for ChangeConflictException
  3. In the catch block use RefreshMode to resolve conflict issue.


You can do concurrency check as follows.

Modify SubmitChanges

You have submitchnages() overloaded and it takes ConflictModeenum as value.

ConfLinq4.gif

If you examine ConflictModeenum:

ConfLinq5.gif

It has two values:

ConfLinq6.gif

Usually you use ConflictModeenum with submitchage as below:

ConfLinq7.gif

Put SubmitChanges in try catch

After modifying SubmitChanges, on the conflict ChangeConflictExceptionwill be thrown by LINQ.

ConfLinq8.gif

Handle the conflict in Exception

In the Exception block you need to handle or resolve the conflict.

RefreshMode enumeration helps you to decide how to handle th conflict. It has three values to resolve the conflict.

ConfLinq9.gif


ConfLinq10.gif

Consider a very simple update operation as below with breakpoint:

ConfLinq11.gif

Run the code and when the code hits breakpoint go to the database and change the value of FirstName for PersonID = 1.
After that change has been made in the database then come back to the code and run from the breakpoint. You will very likely encounter the following exception at the submitChanges() method call:

ConfLinq12.gif

Essentially what we did is that we took the data in the DataContext and then modified the value from another source which caused a concurrency conflict.

If we put all the discussion together we can handle conflict as below:

using System;
using System.Linq;
using System.Data.Linq;

namespace Concurrency
{
    class Program
    {
        static void Main(string[] args)
        {

            DataClasses1DataContext context = new DataClasses1DataContext();

            #region without handling Conflict
            //Person personToUpdate = (from r in context.Persons
            //                         where r.PersonID == 1
            //                         select r).FirstOrDefault();
            //personToUpdate.FirstName = "John Papa";
            //context.SubmitChanges();

            #endregion 

            #region hanlding conflict 

            try
            {
                Person personToUpdateConflict = (from r in context.Persons
                                                 where r.PersonID == 1
                                                 select r).FirstOrDefault();
                personToUpdateConflict.FirstName = "JohnPapa";
                context.SubmitChanges(ConflictMode.FailOnFirstConflict);

            }
            catch (ChangeConflictException c)
            {
                foreach (ObjectChangeConflict o in context.ChangeConflicts)
                {
                    o.Resolve(RefreshMode.KeepChanges);
                    
                }
                context.SubmitChanges();

            }

            #endregion 
            Console.ReadKey(true);
        }
    }
}


Now you know how to resolve conflicts in LINQ. I hope this article was useful. Thanks for reading.

Up Next
    Ebook Download
    View all
    Learn
    View all