This is the 19th post in my ongoing series of Entity Framework Tips.

Background:

If you have a table with a timestamp column, and you reverse engineer an Entity from that table, you will end up with a Binary property in your entity (in my example called Version).

If you look at the properties window for that property you will see something like this:

ConcurrencyModeFixed

The interesting thing here is the Concurrency Mode. The Entity Framework support 2 Concurrency Modes:

  • None – This is the default and means the property is not involved in any concurrency checks
  • Fixed – Which means that the original value of this property is sent as part of the WHERE clause in all updates or deletes

So timestamps have a Concurrency Mode of Fixed, which means the original value loaded from the database is included in the WHERE clause of any Updates or Deletes.

If you delve a little deeper by looking at the Storage Model (aka SSDL), which you can see if you open your EDMX in the XML editor, you will notice something else, namely that the Version property has a StoreGeneratedPattern of Computed.

There are 3 possible StoreGeneratedPatterns:

  • None – This is the default and by far the most common. It means that this column is not generated in the database.
  • Identity – This means that when the EF does inserts the database will generate a value. So after an insert the EF will get the generated value and feed it back into the Entity. This setting is frequently used for primary keys that are automatically generated in the database.
  • Computed – This means that whenever the EF does insert OR update the store will generate a new value. So the EF will feed the generated value back into the entity after both inserts AND updates. Yes you guessed it this is generally used for things like Timestamps.

So because timestamps have a StoreGeneratedPattern of Computed, whenever the EF Inserts or Updates an entity with a timestamp column it will automatically get the latest timestamp value and feed it back into the Entity.

Handling Optimistic Concurrency Exceptions:

In the example below I have an Entity called Post that has a timestamp column called Version. Given that this simple code:

using (TipsEntities ctx1 = new TipsEntities())
{
    // Get a post (which has a Version Timestamp) in one context
    // and modify.
 
    Post postFromCtx1 = ctx1.Post.First(p => p.ID == 1);
    postFromCtx1.Title = "New Title";

    // Modify and Save the same post in another context 
    // i.e. mimicking concurrent access.
    using (TipsEntities ctx2 = new TipsEntities())
    {
        Post postFromCtx2 = ctx2.Post.First(p => p.ID == 1);
        postFromCtx2.Title = "Newer Title";
        ctx2.SaveChanges();
    }
    // Save the changes... This will result in an Exception
    ctx1.SaveChanges();
}

… will cause an OptimisticConcurrencyException:

OptimisticConcurrencyExceptionHeader

… now if we delve a little deeper, by clicking ‘View Detail’ you will see that the OptimisticConcurrencyException gives you access to the ObjectStateEntry(s)associated with the Entity(s) that caused the concurrency exception via the StateEntries property:

OptimisticConcurrencyException

Which means that if you want to handle this sort of situation gracefully you simply trap the OptimisticConcurrencyException and grab the Entity(s) related to those StateEntries so you can provide some sort of message:

catch (OptimisticConcurrencyException ex) {
    ObjectStateEntry entry = ex.StateEntries[0];
    Post post = entry.Entity as Post;
    Console.WriteLine("Failed to save {0} because it was changed in the database", post.Title);
}

Pretty simple if you ask me.

Of course in the real world things are seldom this simple. Your requirements probably states that you have to give the user the ability to compensate and retry. How do you do that exactly?

Well that is definitely an interesting scenario, so expect another tip soon.