Concurrency in Entity Framework:
Entity Framework supports Optimistic Concurrency by default. In the optimistic concurrency, EF saves the entity to the database, assuming that the same data has not changed since the entity was loaded. If it determines that the data has changed, then an exception is thrown and you must resolve the conflict before attempting to save it again.
Let's see how to handle optimistic concurrency with Student entity.
First of all, you need to have a rowversion column in the Student table in order to handle concurrency with Student entity. Rowversion is a datatype in the SQL Server that automatically generates unique binary number whenever the insert or update operation is performed in a table. The rowversion datatype is simply an incrementing number. Rowversion is a similar to the timestamp datatype.
Create a new column RowVersion in Student table with timestamp datatype as shown below:
Note: The value of RowVersion will be added and updated automatically by the database during the Insert and Update operation.
Now, create a new Entity Data Model as shown in Create Entity Data Model section or if you already have an EDM then update it by right clicking on designer -> Update Model From Database -> Refresh Student table. Now, you will see the RowVersion property added in the Student entity.
Then, you need to set the concurrency mode to fixed by right clicking on RowVersion property in the Student entity (right click on RowVersion property not Student entity) -> select Property. Change Concurrency Mode to Fixed from None in the property window as shown below:
EF will now include a RowVersion column in the where clause, whenever you do an update operation and if the rowversion value is different than in the where clause then it will throwDbUpdateConcurrencyException.
The following code shows that User1 and User2 get the same student and update StudentName at the same time:
Student student1WithUser1 = null; Student student1WithUser2 = null; //User 1 gets student using (var context = new SchoolDBEntities()) { context.Configuration.ProxyCreationEnabled = false; student1WithUser1 = context.Students.Where(s => s.StudentID == 1).Single(); } //User 2 also get the same student using (var context = new SchoolDBEntities()) { context.Configuration.ProxyCreationEnabled = false; student1WithUser2 = context.Students.Where(s => s.StudentID == 1).Single(); } //User 1 updates Student name student1WithUser1.StudentName = "Edited from user1"; //User 2 updates Student name student1WithUser2.StudentName = "Edited from user2";
User1 saves his changes before User2. So when user2 tries to save the changes, he will get concurrency exection:
//User 1 saves changes first using (var context = new SchoolDBEntities()) { try { context.Entry(student1WithUser1).State = EntityState.Modified; context.SaveChanges(); } catch (DbUpdateConcurrencyException ex) { Console.WriteLine("Optimistic Concurrency exception occured"); } } //User 2 saves changes after User 1. //User 2 will get concurrency exection //because CreateOrModifiedDate is different in the database using (var context = new SchoolDBEntities()) { try { context.Entry(student1WithUser2).State = EntityState.Modified; context.SaveChanges(); } catch (DbUpdateConcurrencyException ex) { Console.WriteLine("Optimistic Concurrency exception occured"); } }
Concurrency in Code-First:
You can create a timestamp property in code-first by using [Timestamp] attribute. Make sure that the property type is byte[] because timestamp is binary in C#.
[Timestamp] public byte[] RowVersion { get; set; }
EF includes a property in the where clause, during the update operation, if the property is marked with the Timestamp attribute.
You can resolve concurrency exceptions many ways. Visit msdn for detailed information on how to resolve optimistic concurrency.
Download sample project for the basic tutorials.