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?