一尘不染

使用事务还是SaveChanges(false)和AcceptAllChanges()?

c#

我一直在研究交易和看来,他们照顾自己的EF只要我传递falseSaveChanges(),然后调用AcceptAllChanges(),如果没有错误:

SaveChanges(false);
// ...
AcceptAllChanges();

如果出现问题怎么办?我不必回滚,或者一旦我的方法超出范围,交易是否结束?

在事务中途分配的所有intentiy列会如何处理?我想如果有人在我的坏事发生之前在我的事后添加了一条记录,那么这意味着将丢失一个Identity值。

有什么理由TransactionScope在我的代码中使用标准类吗?


阅读 226

收藏
2020-05-19

共1个答案

一尘不染

使用实体框架,大多数时间SaveChanges()就足够了。这将创建一个事务,或加入任何环境事务,并在该事务中完成所有必要的工作。

尽管有时SaveChanges(false) + AcceptAllChanges()配对很有用。

最有用的地方是要在两个不同的上下文之间进行分布式事务的情况。

即像这样(不好):

using (TransactionScope scope = new TransactionScope())
{
    //Do something with context1
    //Do something with context2

    //Save and discard changes
    context1.SaveChanges();

    //Save and discard changes
    context2.SaveChanges();

    //if we get here things are looking good.
    scope.Complete();
}

如果
context1.SaveChanges()成功但context2.SaveChanges()失败,则整个分布式事务将中止。但是很遗憾,实体框架已经放弃了对的更改context1,因此您无法重播或有效地记录故障。

但是,如果您将代码更改为如下所示:

using (TransactionScope scope = new TransactionScope())
{
    //Do something with context1
    //Do something with context2

    //Save Changes but don't discard yet
    context1.SaveChanges(false);

    //Save Changes but don't discard yet
    context2.SaveChanges(false);

    //if we get here things are looking good.
    scope.Complete();
    context1.AcceptAllChanges();
    context2.AcceptAllChanges();

}

在调用SaveChanges(false)将必要的命令发送到数据库时,上下文本身不会更改,因此您可以在必要时再次进行操作,也可以根据需要进行询问ObjectStateManager

这意味着,如果事务实际上抛出异常,您可以通过在ObjectStateManager某个地方重试或记录每个上下文的状态来进行补偿。

有关更多信息,请参见我的
博客文章

2020-05-19