Properly handling DbUpdateConcurrencyException

Viewed 1316

This is from docs about lifetime of DBContext:

When working with Windows Presentation Foundation (WPF) or Windows Forms, use a context instance per form. This lets you use change-tracking functionality that context provides.

I've read that lifetime of a DBContext should be short as possible, but obviously in the case of WinForms (which I am using), this rule doesn't apply and it is recommended something else.

The Current Setup

Also my application follows MVC pattern and in my Controller, I have initialized DBContext. Now when the form is closed, among other things, the controller instance is disposed as well, and that is where context dies. Also I am using Database First approach, if matters.

Now having a context always opened (per form) seems that it has its own conveniences (you can easily track changes on a context), but for example, I find myself (as an EF beginner) in some doubts... Take a look at this situation:

I have IList of users (user entity) that is initialized when the form is created. And I run two (or even more) instances of my application because it is meant to work in multi-user environment. Now, say that user A and user B, both load the same record (user management screen, so both of them are admins)... Now when things go like this:

user A makes changes (update) on some record user B makes changes (update) on the same record and save it to a database user A tries to save a DbUpdateConcurrencyException is thrown...

Now this is fine, I am aware of a term Optimistic Concurrency, and say that both user A and B were updating the same row (or same column), I would handle an exception like this (correct me if I am missing something):

catch (DbUpdateConcurrencyException ex)
{
    ex.Entries.Single().Reload();
    //Here I reload UI with a new changes, and ask a user to try again         
}

Now this seem to be working... Because my context is opened as long as my form is alive, when I do Reload() on ex.Entries.Single(), a specific user from a list (remember that I have mentioned a list of users before) is refreshed with actual database values, so when I reload the view, the user gets the current state.

The Actual Problem

So far so good...But for example in this situation where:

user A deletes the row

user B tries to update and save the changes on the same (already deleted row)

I run into multiple problems, and I don't know what would be a right way to handle it.

I guess, I should update the users list, but don't know how to do this without disposing a current context. So that would be a question... How to reload user list from a database, without disposing a context in this block of code:

catch (DbUpdateConcurrencyException ex)
{
    // Reload the user list with navigation properties fully initialized (note that user list is what would context.korisnik.ToList() would return)
    // Reload the UI
}

What would be a proper way to handle Optimistic Concurrency errors in situations like this?

0 Answers
Related