Farhad Alizadeh Noori
Farhad Alizadeh Noori

Reputation: 2306

Entity Framework Optimistic Concurrency Exception Handling

I'm trying to solve an issue with the optimistic concurrency control on EF 6. I currently want to catch the DBUpdateConcurrencyException and then refresh the entity. However I am currently getting this Exception:

System.InvalidOperationException: The element at index 0 in the collection of objects to refresh has a null EntityKey property value or is not attached to this ObjectStateManager.

Here is a simplified version of the code that shows the purpose:

using (var dbContextTransaction = dbContext.Database.BeginTransaction(System.Data.IsolationLevel.Serializable))
{
    try
    {
        dbContext.Commit();
    }
    catch(DbUpdateConcurrencyException ex)
    {
        ((IObjectContextAdapter)KnowledgebaseContext).ObjectContext.Refresh(RefreshMode.StoreWins, en);
        dbContextTransaction.Rollback();
    }
}

I couldn't find much on this exception on Google or SO. Any help would be appreciated.

Upvotes: 3

Views: 8303

Answers (1)

Farhad Alizadeh Noori
Farhad Alizadeh Noori

Reputation: 2306

I have been able to solve this problem by looking at this and this. The documentation on this feature is rather scarce.

So here is the scenario(we assume that there already is a TimeStamp column the value of which gets updated with each database update):

UserA reads Entity1 and starts making changes. While UserA is making her changes, userB reads Entity1, changes it and saves it to the database. Now UserA wants to save her changes but now by definition, the exact entity that she read no longer exists. The reason for this is that the existence of that entity depends on the TimeStamp column as well which is no longer the same old value. So when I was trying to refresh Entity1 as UserA knew existed, I was getting an exception and I was not able to Refresh either.

Now we'll look at two possible solutions to a concurrency problem for an existing updated entity:

  • Ignore UserA's Changes(store wins): This basically means that one will Refresh the entity from the database. In order to do this, one should overwrite the TimeStamp field for Entity1 in UserA's context with the new one now residing on the database and then try to refresh the information from the server. This way the right entity can be located and retrieved and populated in Entity1 overwriting local changes. Look here for another approach than this.
  • Overwrite changes on the database(client wins): Here, we would overwrite the TimeStamp field and then attempt the update again. By doing so, the EF would no longer detect the update as a conflict and the data on the server is overwritten. The previously referred links contain examples for this case as well.

I don't know exactly for sure why I was getting the exception when using the Refresh method. I switched to using SetValues and GetDatabaseValues and such and my problem was solved.

Upvotes: 2

Related Questions