情景:
显然在上面的示例中,调用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
}
答案 0 :(得分:1)
你绝对应该为此使用新的上下文。上下文是工作单元,一旦您的业务逻辑说:“嘿,我不想更新此实体”,那么该实体不是工作单元的一部分。您可以分离实体或创建新上下文。
有可能使用Refresh
方法,但该方法应该用于必须处理乐观并发的情况。因此,如果实体的一部分,此方法仅刷新标量和复杂属性以及外键 - 如果您对导航属性进行了更改,则在刷新实体后这些属性仍然存在。
答案 1 :(得分:0)
使用RefreshMode.StoreWins看一下ObjectContext.Refresh我认为这会做你想要的。开始一个新的上下文会实现我想的相同的事情,但不是那么整洁。