Handling Concurrency in LINQ to SQL -Part 3


In my earlier articles I showed how we can handle the concurrency using UpdateCheck. In this articles I will show how to deal with Concurrency Exceptions.

In using the Always or WhenChanged options for UpdateCheck, it is inevitable that two users will modify the same values and cause conflicts. In those cases, the DataContext will raise a ChangeConflictException when the second user issues   an SubmitChanges request. Because of the likelihood of running into an exception, we need to make sure we wrap the updates inside a structured exception handling block.

Once an exception is thrown, several options to resolve the exception exist. The DataContext helps discover not only the objects that are in conflict, but also which properties are different between the original value, the changed value, and the current value in the database. In order to provide this level of information, we can specify the “RefreshMode” to determine whether the conflicting record is first refreshed from the database to determine the current values. Once we have the refreshed values, we can determine whether we want to retain the original values, the current database values, or our new values. If we want to take the last option and make sure our values are the ones that are retained, we resolve the change conflicts of the context object specifying that we want to keep the changes as shown in the code below.

5

 If we use the RefreshMode.KeepChanges option, we don’t need to inspect the changed values. We are assuming that our values are correct and go ahead and force them into the appropriate row. This can be potentially dangerous. Columns that we didn’t update will be refreshed from the current value in the database. If the business needs demand it, we could merge the changes with the new values from the database; simply set the RefreshMode as  RefreshMode.KeepCurrentValues. This way, we’ll incorporate the other user’s changes into our record and add our changes. However, if both users changed the same column, the new value will overwrite the value that the first user updated. To be safe, we can overwrite the values that the second user tried to change with the current values from the database. In that case, use  RefreshMode.OverwriteCurrentValues  At this point, it would not be beneficial to submit the changes back to the database again, as there would be no difference between the current object and the values in the database. We would present the refreshed record to the user and have them make the appropriate changes again.Depending on the number of changes that the user made, they may not appreciate having to reenter their data. Since SubmitChanges can update multiple records in a batch, the number of changes could be significant. To assist with this, the SubmitChanges method takes an overloaded value to indicate how we wish to proceed when a record is in conflict. We can either stop evaluating further records or collect a listing of objects that were conflicted.  

The ConflictMode enumeration specifies the two options: FailOnFirstConflict and ContinueOnConflict. 

With the ContinueOnConflict option, we’ll need to iterate over the conflicting options and resolve them using the appropriate RefreshMode. With this method, we can at least submit some of the values and then prompt the user to reenter his information in the conflicting items. This could still cause some user resentment, as he would need to review all of the changes to see what records need to be changed.A better solution would be to present the user with the records and fields that were changed. LINQ to SQL not only allows access to this information, but also supports the ability to view the current value, original value, and database value for the conflicting object. The below code demonstrates using the ChangeConflicts collection of the DataContext to collect the details of each conflict. 6

Each item in the ChangeConflicts collection contains the object that conflicted as well as a MemberConflicts collection. This collection contains information about the Member, CurrentValue, DatabaseValue, and OriginalValue. Once we have this information, we can display it to the user in whatever method we choose. Using this code, we can display details of the concurrency errors that the user creates.In designing systems that allow for multiple concurrent users, we need to consider how to handle concurrency concerns.  By catching the exception, we can either handle it using one of the resolution modes or roll the entire transaction back.

Advertisements
This entry was posted in .NET Framework, LINQ. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s