Practical ASP.NET

Handling Concurrency with Entity Framework

If you want to use Entity Framework in ASP.NET, you're going to need to handle concurrency problems. Here are some suggestions from a Microsoft "architect evangelist."

To effectively use Entity Framework (EF) in ASP.NET, we need to handle two problems: tracking changes and handling data concurrency. The tracking changes problem occurs because EF's ObjectContext keeps track of what data was originally retrieved from the database and what's been changed. You could hang on to the ObjectContext while the user is looking at the data in the page, but that would consume memory on the server for every retrieved object in the ObjectContext (and Microsoft's best practice for working with the ObjectContext is to dispose of it quickly; I have to assume there's a reason for that).

Alternatively, when the user submits the page, you could re-fetch the data from the database before applying changes -- simple, but it requires an extra trip to the database server, which is bad for scalability. I also tend to obsess about managing data when two people access the same row at the same time.


In ASP.NET, concurrency is a thorny problem. To start with, we send the data down to the user who can spend an indeterminate time looking at it while completely disconnected from the application. And in ASP.NET, users can wander off to another site or shut down their browsers without notifying us that they're done with the data. As a result, we don't want to lock records while a user has them (see " Never Lock Records in Web Applications! Never! That Means You! ").

I've discussed solutions in the past. Most recently, I looked at how to use the ASP.NET ObjectDataSource to ensure that you only update fields that have actually changed ("Handling Concurrency with the ObjectDataSource"). However, that left some readers hanging. They want to prevent updates in case one user changes the data while another user was preparing their changes by using optimistic concurrency (see "Handling Data Contention with Optimistic Concurrency").

Tracking Changes
I've pulled one solution for tracking changes with the EF from Cesar de la Torre's blog. What Cesar is doing is making copies of individual EF entity objects related to the page the user is viewing and storing those objects in the Session. Keeping only the objects displayed on the page substantially reduces the overhead in holding objects in memory.

Cesar's code for creating a copy of an EF entity consists of serializing the Entity object to a MemoryStream (using the DataContractSerializer) and then, later, retrieving that version of the object from the stream. This example (in Visual Basic; Cesar's blog has a C# version) copies an Orders object held in the variable ord to a MemoryStream held in the Session object:

Dim dcs as System.Runtime.Serialization.DataContractSerializer 
dcs = New System.Runtime.Serialization.DataContractSerializer(ord.GetType())
Dim ms As System.IO.MemoryStream 
ms = New System.IO.MemoryStream
dcs.WriteObject(ms, ord)
Me.Session(ord.OrderId.ToString) = ms

On postback, you can de-serialize the object and re-attach it to a new instance of the ObjectContext using the ObjectContext's Attach method. Re-attaching an object to a recreated ObjectContext looks like this:

Dim ms As System.IO.MemoryStream
ms = CType(Me.Session(Me.OrderIdTextBox.Text), System.IO.MemoryStream)
ms.Position = 0
Dim ord2 As Orders
ord2 = CType(dcs.ReadObject(ms), Orders)

ob.Attach(ord2); 

At this point, you can check for changes made in the user interface and apply the changes from the object returned from ObjectDataSource. If you check for changes earlier in the process (as described in my column on the ObjectDataSource) you can skip the de-serialization and update process.

Handling Concurrency in EF
But what about concurrency? The solution that many of my readers have liked is what Microsoft calls "optimistic concurrency": building a Where clause in the SQL statements that checks to see if any fields have changed since the user retrieved the record. As I discussed in that earlier column on optimistic concurrency, you only really need to check one field: the row's timestamp which is changed each time a row is modified.

The good news is that you can get EF to incorporate the original value of any field into the Where clause that it generates. In the EF designer, click on the property in the Entity Object that represents the timestamp and set its Concurrency mode to Fixed. You just need to make sure that (a) your tables have a timestamp field and (b) that it's one of the properties on your Entity objects.

Unlike the ASP.NET SqlDataSource, where optimistic concurrency is a silent failure, with EF when a record isn't found because of a concurrency failure, an OptimisticConcurrencyException is raised. So, with the timestamp field flagged as Fixed, you should now be able to write code like this to handle updating the database with the user's changes:

Dim ob As New OrderEntities
... re-attach Entity objects and apply changes...
Try	
    ob.SaveChanges
Catch ex As System.Data.OptimisticConcurrencyException
   Me.ErrorLabel.Text = "Changes lost."
   ...refresh the page...
End Try


About the Author

Peter Vogel is a principal in PH&V Information Services, specializing in ASP.NET development with expertise in SOA, XML, database, and user interface design. His most recent book ("rtfm*") is on writing effective user manuals, and his blog on technical writing can be found at rtfmphvis.blogspot.com.

Reader Comments:

Mon, Feb 15, 2010 Bill USA

Thank you for a great article! I would like to get your ideas on the following... We are following the pattern of placing a timestamp on each entity (record). We plug into the OnChanged methods to ensure that a new timestamp is generated to reflect any changes. The problem is that, when an entity is instantiated, EF also calls the OnChanged methods. This results in all entities being marked as modified. One solution that I am considering is:
Not having the OnChanging methods update the timestamp but rather defining an IConcurrencyTimestamp interface on my entities with the method UpdateConcurrencyTimestamp(). Then plugging into the context_SavingChanges event and calling the UpdateConcurrencyTimestamp method for those entities that implement it. Seems like I might be missing something. Is there a better solution to this problem.

Mon, Jul 6, 2009 cowgaR

well, as has been thousand times said by devs most notably ORM guru Frans Bauma, concurency should be a Framework thing! it shouldn't be on the shoulders of the Framework users, in that case EF is nothing just a platform. And why use it when there are dozen of much better ORMs out there which in case of, say, NHibernate, are even free! and btw, Visual Basic is killing the sanity in me ;p any change in EF v4.0?

Sun, Jun 21, 2009 Peter Vogel Canada

Thanks for pointing out the typo! We've fixed it.

Fri, May 29, 2009 Dr Bob Hacker Central Texas

Great and useful article! A nit: timestamp file should be timestamp field. I always enjoy reading your stuff!Bob

Add Your Comments Now:

Your Name:(optional)
Your Email:(optional)
Your Location:(optional)
Comment:
Please type the letters/numbers you see above