'Using EF Core with WPF and I'd like to revert to initial state when a user press Cancel instead of OK on a dialog, is that possible and how?

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 can choose "OK" or "Cancel". On OK I just do ctx.SaveChanges(). But for Cancel, how can I revert back every changes? How to 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 and there should be a better way to achieve the task more efficently by using changes tracked by the DbContext?

I found GitHub-dotnet/efcore request: Implement RejectChanges() in DbContext #14594. but it does'nt seems 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 few trials and errors (like having a singleton Context), I decided to go with something that would require more works 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().



Solution 1:[1]

Q: Is that possible and how?

A: Sure.

  1. The most straightforward way is to only "SaveChanges()" when you're "Done" (when the user clicks "OK").

  2. Another approach might be to make copies of the original objects, and perform in-process operations on the copies.

  3. 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://docs.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
}

Solution 2:[2]

You can use the ChangeTracker to retrieve all tracked EntityEntries. Each EntityEntry contains both the CurrentValues and the OriginalValues for all properties. Documentation

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 paulsm4
Solution 2 pjs