如何将ef4上下文或至少一些实体恢复为原始值?

时间:2011-06-14 18:46:47

标签: c# asp.net entity-framework entity-framework-4

情景:

  1. 检索某些实体
  2. 更新这些实体的某些属性
  3. 您执行某种业务逻辑,规定您不应再更新这些属性;相反,您应该插入一些记录业务逻辑结果的新实体。
  4. 插入所说的新实体
  5. 的SaveChanges();
  6. 显然在上面的示例中,调用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
    }
    

2 个答案:

答案 0 :(得分:1)

你绝对应该为此使用新的上下文。上下文是工作单元,一旦您的业务逻辑说:“嘿,我不想更新此实体”,那么该实体不是工作单元的一部分。您可以分离实体或创建新上下文。

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

答案 1 :(得分:0)

使用RefreshMode.StoreWins看一下ObjectContext.Refresh我认为这会做你想要的。开始一个新的上下文会实现我想的相同的事情,但不是那么整洁。