I'm using EF Core with WPF and I'd like to revert any changes done on any objects to their initial state when a user press Cancel instead of OK on a dialog, is that possible and how?
I'm using a global singleton DbContext where I load all my data model at the beginning of the application. I do not want to know if I should or should not use a DataContext singleton.
When a user has to do some changes on instances in a database, I present a WPF DialogBox where he/she can choose OK or Cancel. On OK, I just do ctx.SaveChanges(). But for Cancel, how can I revert back every changes? How can I come back to a state where all objects returns to their initial state as when the Dialog was called?
I can Dispose the DataContext (which will flush all changes) and reload everything again, but it takes a lot of time. Is there a better way to achieve the task more efficiently by using changes tracked by the DbContext?
I found a GitHub-dotnet/efcore request: Implement RejectChanges() in DbContext #14594. but it doesn’t seem to have any solution.
I think the proper solution should be close to this answer for EF (not core): DbContext discard changes without disposing. I will try to code it (if possible) but an already properly coded solution, and debugged, would be so great!
Update 2022-05-27
After a few trials and errors (like having a singleton Context), I decided to go with something that would require more work, but that with be more in line with the EF Core philosophy. In my case, I load the full model (almost) in memory with "NoTracking". Then when I want to edit an instance (entity), I do so by copying it and makes modification on the copy. If the user choose to apply modifications, then I open a Context and attach to the entity to edit, apply changes to the original entity (copy changes from the copy), and then Ctx.SaveChanges and then Dispose().
Q: Is that possible and how?
A: Sure.
The most straightforward way is to only "SaveChanges()" when you're "Done" (when the user clicks OK).
Another approach might be to make copies of the original objects, and perform in-process operations on the copies.
If you're continually updating and saving work-in-progress to the DB (possibly an unwise design), then you can also leverage transactions, and rollback if the user hits Cancel.
Example:
https://learn.microsoft.com/en-us/ef/core/saving/transactions
using var context = new BloggingContext(); using var transaction = context.Database.BeginTransaction(); try { context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" }); context.SaveChanges(); context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/visualstudio" }); context.SaveChanges(); var blogs = context.Blogs .OrderBy(b => b.Url) .ToList(); // Commit transaction if all commands succeed, transaction will auto-rollback // when disposed if either commands fails transaction.Commit(); } catch (Exception) { // TODO: Handle failure }