2012-09-22 97 views
3

我想在我的应用程序中实现实体框架,我应该能够提交和手动回滚更改。实体框架使用BeginTransaction()

第一次当我执行更新语句它成功更新表,我能够回滚更改。 这是正确的

但第二次当我执行更新语句时,它成功更新表并提交更改。所以我无法手动回滚。 这是不对的

请让我知道它为什么会发生以及如何解决这个问题。

下面的代码只是示例来重现我的问题。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Data.Common; 
using System.Data; 

namespace EFTest 
{ 
    public class DBOperations 
    { 
     NorthwindEntities NorthwindContext; 
     DbTransaction transObject; 

     public DBOperations() 
     { 
     } 

     public void ConnectDB() 
     { 
      try 
      { 
       if (NorthwindContext == null) 
       { 
        NorthwindContext = new NorthwindEntities(); 
        if (NorthwindContext != null && NorthwindContext.Connection.State != ConnectionState.Open) 
        { 
         NorthwindContext.Connection.Open(); 
         transObject = NorthwindContext.Connection.BeginTransaction(IsolationLevel.ReadUncommitted); 
        } 
       } 
      } 
      catch (Exception ex) 
      { 
       throw new Exception("Database Error " + ex.Message); 
      } 
     } 

     public int disconnect() 
     { 
      if (NorthwindContext != null && transObject != null) 
      { 
       try 
       { 
        transObject.Rollback(); 
       } 
       catch (Exception) 
       { 
       } 
       transObject.Dispose(); 
       NorthwindContext.Connection.Close(); 
       NorthwindContext.Dispose(); 
      } 

      return 0; 
     } 

     public void CommitTransaction() 
     { 
      if (NorthwindContext != null && transObject != null) 
      { 
       try 
       { 
        transObject.Commit(); 
       } 
       catch (Exception) 
       { 
       } 
      } 
     } 

     public void RollbackTransaction() 
     { 
      if (NorthwindContext != null && transObject != null) 
      { 
       try 
       { 
        transObject.Rollback(); 
       } 
       catch (Exception) 
       { 
       } 
      } 
     } 

     public int UpdateDB() 
     { 
      int _returnVal = 0; 


      try 
      { 
       NorthwindContext.ExecuteStoreCommand("UPDATE Orders SET OrderDate = GETDATE() WHERE OrderID = '10248'"); 
      } 
      catch (Exception ex) 
      { 
       throw new Exception("Database Error " + ex.Message); 
      } 

      return _returnVal; 
     } 
    } 

    public class program 
    { 
     public program() 
     { 
      //Establishing the connection. 
      DBOperations _DBOperations = new DBOperations(); 
      _DBOperations.ConnectDB(); 

      //Update the datebase 
      _DBOperations.UpdateDB();       //Update the database but it doesn't commit the changes.      

      //Issue Rollback to rollback the transaction. 
      _DBOperations.RollbackTransaction();    //Successfully Rollbacks the database changes. 


      //Again Update the datebase 
      _DBOperations.UpdateDB();       //Update the database it commits the changes. 

      //Issue Rollback to rollback the transaction. 
      _DBOperations.RollbackTransaction();    //Rollback fails. 

     } 
    } 
} 
+0

使用['TransactionScope'](http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx) –

+0

@GertArnold是的我想过,但如何手动提交或回滚使用TransactionScope的? – ksvimal

+0

要提交,你只需要'Complete()'一个事务范围。如果您丢弃未完成的TS回滚。 –

回答

1

您需要在提交或回滚事务后分配新事务。

public program() 
{ 
    //Establishing the connection. 
    DBOperations _DBOperations = new DBOperations(); 
    _DBOperations.ConnectDB(); 

    //Update the datebase 
    _DBOperations.UpdateDB(); //Update the database but it doesn't commit the changes. 

    //Issue Rollback to rollback the transaction. 
    _DBOperations.RollbackTransaction(); //Successfully Rollbacks the database changes. 

    _DBOperations.ConnectDB(); //you need to assign new transaction because your last 
           //transaction is over when you commit or roll back 

    _DBOperations.UpdateDB(); //Update the database it commits the changes. 

    //Issue Rollback to rollback the transaction. 
    _DBOperations.RollbackTransaction(); //Rollback fails. 
} 
+1

非常感谢您的反馈......因此,即使提交和回滚的次数尽可能多,我也不可能使用相同的事务对象......这是正确的吗? – ksvimal

1

随着TransactionScope你DbOperations看起来是这样的:

public class DBOperations : IDisposable 
{ 
    NorthwindEntities _context; 
    private TransactionScope _transactionScope; 

    public DBOperations() 
    { 
     this.Initialize(); 
    } 

    private void Initialize() 
    { 
     try 
     { 
      this.Dispose(); 
      this._transactionScope = new TransactionScope(); 
      this._context = new NorthwindEntities(); 
      // no need to open connection. Let EF manage that. 
     } 
     catch (Exception ex) 
     { 
      throw new Exception("Database Error " + ex.Message); 
     } 
    } 

    public void RollbackTransaction() 
    { 
      try 
      { 
       this._transactionScope.Dispose(); 
       this._transactionScope = null; 
       this.Dispose(); 
       this.Initialize(); 
      } 
      catch (Exception) 
      { 
       // TODO 
      } 
    } 

    public int UpdateDB() 
    { 
     int _returnVal = 0; 
     try 
     { 
      this._context.ExecuteStoreCommand("UPDATE Orders SET OrderDate = GETDATE() WHERE OrderID = '10248'"); 
     } 
     catch (Exception ex) 
     { 
      throw new Exception("Database Error " + ex.Message); 
     } 
     return _returnVal; 
    } 

    public void Dispose() 
    { 
     if (this._transactionScope != null) 
     { 
      this._transactionScope.Complete(); 
      this._transactionScope.Dispose(); 
     } 
     if (this._context != null) this._context.Dispose(); 
    } 
} 

而且程序:

public class program 
{ 
    public program() 
    { 
     using (DBOperations dbOperations = new DBOperations()) 
     { 
      dbOperations.UpdateDB(); // Update the database no commit. 

      dbOperations.RollbackTransaction(); // Rollback. 

      dbOperations.UpdateDB(); // Update the database no commit. 

      dbOperations.RollbackTransaction(); // Rollback. 
     } // Commit on Dispose. 
    } 
} 

是一个TransactionScope的范围内自动打开的事务中登记的连接。交易是只有承诺致电Commplete()。处置或未处理的异常将导致回滚。

如果您不仅仅是一个存储命令,而且还要改变对象并依赖上下文的变更跟踪,您可以实现一个重试机制,而不仅仅是放弃上下文和更改。

+0

不,我正在使用Context.SaveChanges(),但在一种情况下,我正在使用store命令来检查某个特定行是否被锁定在表中。我对EntityframeWork很陌生,所以我正在尝试构建最佳逻辑。我认为有多个上下文实例是好的,每个屏幕可以是一个上下文。这是对的吗?如果我错了,请纠正我 – ksvimal

+0

是的,上下文实例来来去去。它们应该是短暂的。每个Web请求一个或每个服务呼叫一个。 Windows应用程序每个屏幕一个可能会工作(因为通常会发生延迟加载),但即使如此,最好加载所需的内容然后进行处理。 –

+0

非常感谢您的反馈。它的确帮助我理解EF。但是我有很多关于EF的问题。你会帮我吗? – ksvimal