2012-09-22 94 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