实体框架、事务和存储过程

本文关键字:存储过程 事务 框架 实体 | 更新日期: 2023-09-27 18:07:24

我有一个存储过程,它根据来自另一个表的值将数据写入一个表。因此,它从表中读取开始/结束日期,然后创建大量数据并将其写入单独的表。

所发生的是用户为某事选择开始/结束日期,然后我将开始/结束日期存储到一个表中。然后从EF中调用存储过程,该过程从刚刚更新的表中读取数据,并填充另一个表。

如果进程失败,我想回滚进程写的所有数据,以及表的初始更新。

我认为数据只写入表(初始更新,在EF中完成),当你调用'SaveChanges'。所以我调用它,然后调用这个过程。是否有一种方法可以检测过程是否失败,如果失败,则回滚所有更新(表更新和过程所做的任何事情)?

目前,我的代码看起来像这样,但似乎SaveChanges中的参数是无效的(没有参数),并且'AcceptAllChanges'是无效的:

using (var scope = new TransactionScope())
{
    Context.SaveChanges(false);
    Context.project_scheduled_event_payments(st.id);
    Context.AcceptAllChanges();
}

实体框架、事务和存储过程

可以使用事务作用域。您需要添加对System.Transactions.dll的引用并添加using System.Transactions;

从msdn:

如果您调用SaveChanges()或SaveChanges(true), EF只是假设如果它的工作完成得很好,一切都很好,它会的放弃它一直跟踪的更改,并等待新的更改。

不幸的是,如果在其他地方出了问题事务,因为EF丢弃了它正在跟踪的更改,我们不能恢复。

这就是SaveChanges(false)和AcceptAllChanges()的用武之地。

SaveChanges(false)告诉EF执行必要的数据库命令,但保留更改,以便可以重播必要的。

现在,如果更广泛的事务失败,您可以重试EF特定的另外调用SaveChanges(false)。或者你可以遍历状态管理器以记录失败的内容。

一旦更广泛的事务成功,您只需调用手动的AcceptAllChanges(),以及正在跟踪的更改被丢弃。

using (TransactionScope scope = new TransactionScope()) 
{ 
    //Do something with context1 
    //Save Changes but don't discard yet 
    context1.SaveChanges(false); 
    //run your secondary procedure, if it succeeds then:    
    //
    //
    context1.AcceptAllChanges(); 
}

edit:好吧,以上将不起作用,因为.SaveChanges(false)ObjectContext方法(也不适合.SaveChanges(SaveOptions)),我们有DbContext。我们知道DbContextObjectContext的包装器,所以我们可以使用IObjectContextAdapter来访问.SaveChanges(SaveOptions)方法:

首先我们需要添加using System.Data.Entity.Infrastructure;,然后:

using (TransactionScope scope = new TransactionScope()) 
{ 
    // do something with your context

    // cast your context to IObjectContextAdapter to get access to the full SaveChanges(SaveOptions) method 
    IObjectContextAdapter contextAdapter = context;
    // .DetectChangesBeforeSave is the equivalent of .SaveChanges(false);
    contextAdapter.ObjectContext.SaveChanges(
        System.Data.Entity.Core.Objects.SaveOptions.DetectChangesBeforeSave);
    //run your secondary procedure, if it succeeds then:    
    //
    //
    contextAdapter.ObjectContext.AcceptAllChanges();
    scope.Complete();
}