将 EF Core 与 WPF 一起使用,当用户在对话框中按“取消”而不是“确定”时,我想恢复到初始状态,这可能吗?如何实现?

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?

我正在将 EF Core 与 WPF 一起使用,当用户在对话框中按下取消而不是确定时,我想将对任何对象所做的任何更改恢复到它们的初始状态,这可能吗?如何实现?

我正在使用全局单例 DbContext,在应用程序开始时加载我的所有数据模型。我不想知道我是否应该使用 DataContext 单例。

当用户必须对数据库中的实例进行一些更改时,我会显示一个 WPF 对话框,用户可以在其中选择“确定”或“取消”。好的,我只是做 ctx.SaveChanges()。但是对于 Cancel,我怎样才能恢复所有更改?如何返回所有对象 returns 到调用对话框时的初始状态?

我可以处理 DataContext(这将刷新所有更改)并再次重新加载所有内容,但这会花费很多时间,应该有更好的方法通过使用 DbContext 跟踪的更改来更有效地完成任务?

我找到 GitHub-dotnet/efcore 个请求:Implement RejectChanges() in DbContext #14594。但似乎没有任何解决办法?

我认为正确的解决方案应该接近 EF(非核心)的这个答案:DbContext discard changes without disposing。我会尝试对其进行编码(如果可能的话),但是一个已经正确编码并经过调试的解决方案会非常棒!

更新2022-05-27

经过几次试验和错误(例如拥有单例上下文)后,我决定采用需要更多工作但更符合 EF Core 理念的东西。就我而言,我使用“NoTracking”将完整模型(几乎)加载到内存中。然后当我想编辑一个实例(实体)时,我通过复制它并在副本上进行修改来做到这一点。如果用户选择应用修改,那么我打开一个上下文并附加到要编辑的实体,将更改应用到原始实体(从副本复制更改),然后 Ctx.SaveChanges 然后 Dispose().

问:这可能吗?如何实现?

答:当然可以。

  1. 最直接的方法是仅在“完成”(当用户单击“确定”时)时“SaveChanges()”。

  2. 另一种方法可能是制作 原始对象的副本,然后对副本执行 in-process 操作。

  3. 如果您不断更新并保存 work-in-progress 到数据库(可能是不明智的设计),那么您还可以利用 transactions,并在用户点击时回滚[取消].

示例:

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
}

您可以使用 ChangeTracker 检索所有跟踪的 EntityEntries。每个 EntityEntry 都包含所有属性的 CurrentValues 和 OriginalValues。 Documentation