如何将ef4上下文或至少某些实体还原为其原始值

本文关键字:还原 实体 原始 ef4 上下文 | 更新日期: 2023-09-27 17:59:04

场景:

  1. 检索一些实体
  2. 更新这些实体的某些属性
  3. 您执行某种业务逻辑,该逻辑指示您不应该再更新这些属性;相反,您应该插入一些新的实体来记录业务逻辑的结果
  4. 插入所述新实体
  5. SaveChanges()

显然,在上面的例子中,调用SaveChanges()不仅会插入新实体,还会更新原始实体的属性。在我设法重新排列代码之前,只有当我确信我希望保存所有更改时,才会对上下文(及其实体)进行更改,但这并不总是可能的。所以问题是,处理这种情况的最佳方式是什么?如果这很重要的话,我不会直接处理上下文,而是通过存储库。有没有一种简单的方法可以将实体恢复为其原始值?在这种情况下,最佳实践是什么?

更新

尽管我不同意Ladislav的观点,即业务逻辑应该以这样的方式重新安排,即验证总是在对实体进行任何修改之前进行,但我同意解决方案应该真正在不同的上下文中坚持所需的更改。我不同意的原因是,我的业务交易相当长,而在交易结束时可能发生的验证或错误检查并不总是显而易见的。想象一下,你正在用自上而下的灯装饰一棵圣诞树,当你在处理较低的树枝时,你已经修改了这棵树。如果其中一盏灯坏了怎么办?您希望回滚所有更改,但希望创建一些ERROR实体。正如Ladislav所建议的,最直接的方法是将ERROR实体保存在不同的上下文中,允许原始实体(带有修改的隐喻树)在不调用SaveChanges的情况下过期。

现在,在我的情况下,我使用Ninject进行依赖性注入,将一个EF上下文注入到顶级服务范围内的所有存储库中。这意味着我的业务层类并不能真正控制创建新的EF上下文。他们不仅不能访问EF上下文(请记住,他们通过存储库工作),而且注入已经发生在对象层次结构的更高层。我找到的唯一解决方案是创建另一个类,该类将利用Ninject在其中创建一个新的UOW

//business logic executing against repositories with already injected and shared (unit of work) context
Tree = treeRepository.Get();
Lights = lightsRepsitory.Get();
//update the tree as you're decorating it with lights
if(errors.Count == 0)
{
    //no errors, calling SaveChanges() on any one repository will commit the entire UOW as they all share the same injected EF context
    repository1.SaveChanges();  
}
else
{
    //oops one of the lights broke, we need to insert some Error entities
    //however if we just add id to the errorRepository and call SaveChanges() the modifications that happened
    //to the tree will also be committed.
    TreeDecoratorErroHandler.Handle(errors);    
}
internal class TreeDecoratorErroHandler
{
    //declare repositories
    //constructor that takes repository instances
    public static void Handle(IList<Error> errors)
    {
        //create a new Ninject kernel
        using(Ninject... = new Ninject...)
        {
            //this will create an instance that will get injected with repositories sharing a new EF instance
            //completely separate from the one outside of this class
            TreeDecoratorErroHandler errorHandler = ninjectKernel.Get<TreeDecoratorErroHandler>();
            //this will insert the errors and call SaveChanges(), the only changes in this new context are the errors
            errorHandler.InsertErrors(errors);
        }       
    }
    //other methods
}

如何将ef4上下文或至少某些实体还原为其原始值

您肯定应该为此使用一个新的上下文。上下文是工作单元,一旦你的业务逻辑说:"嘿,我不想更新这个实体",那么这个实体就不是工作单元的一部分。可以分离实体,也可以创建新的上下文。

有可能使用Refresh方法,但该方法应该用于必须处理乐观并发的场景。因此,如果是实体的一部分,则此方法仅刷新标量和复杂属性以及外键——如果您对导航属性进行了更改,则这些属性在刷新实体后仍然存在。

看看ObjectContext.Refresh with RefreshMode.StoreWins我认为这会达到你想要的效果。我想,开始一个新的环境会达到同样的效果,但不会那么整洁。