2015-09-11 70 views
2

有沒有一種方法來創建一個Disposable對象嵌套使用,所以這段代碼:如何避免重寫相同的使用語句?

using (var ctx = new MyEntities()) 
{ 
    ctx.Connection.Open(); 
    using (var tx = dbContext.Connection.BeginTransaction()) 
    { 
     // ... do awesome things here 

     ctx.SaveChanges(); 
     tx.Commit(); 
    } 
} 

到這樣的事情:

using (var txContext = new TransactionContext()) 
{ 
    // ... do awesome things here 
} 

目前我有:

public class TransactionContext : IDisposable 
{ 
    private MyEntities DbContext { get; set; } 
    private DbTransaction Transaction { get; set; } 

    public TransactionContext() 
    { 
     DbContext = new MyEntities(); 
     DbContext.Connection.Open(); 

     Transaction = DbContext.Connection.BeginTransaction(); 
    } 

    void IDisposable.Dispose() 
    { 
     try 
     { 
      DbContext.SaveChanges(); 
      Transaction.Commit(); 
     } 
     catch (Exception exception) 
     { 
      Transaction.Rollback(); 
      DbContext.Dispose(); 
     } 
    } 
} 

我不知道這是在釋放不同Disposables的方式是正確的,尤其是在一個錯誤/異常的情況。

+1

我想說這個設計的主要問題是,它使用一次性模式不僅僅是處理。如果在'using'中發生異常,那麼將會調用Dispose,現在當你可能不應該調用'SaveChanges'和'Commit'時。請閱讀有關[處理模式]的MSDN文章(https://msdn.microsoft.com/en-us/library/b1yfkh5e(v = VS.110).aspx) – juharr

+1

備註:不要只是*吞下*異常:catch(Exception){... throw;}' –

+0

@juharr:有效的點。你有沒有其他解決方案?最後,它只是爲了避免我一遍又一遍地寫同一行 – KingKerosin

回答

2

這可能會更好地使用一種方法,而不是類。

private static void RunInTransaction(Action<MyEntities, DbTransaction> action) 
{ 
    using (var ctx = new MyEntities()) 
    { 
     ctx.Connection.Open(); 
     using (var tx = ctx.Connection.BeginTransaction()) 
     { 
      action(ctx, tx); 
      ctx.SaveChanges(); 
      tx.Commit(); 
     } 
    } 
} 

然後你可以這樣稱呼它。

RunInTransaction((ctx,tx) => 
{ 
    // ... do awesome things here 
}); 

您還可以創建一個版本,這將返回一個值

private static T RunInTransactionAndReturn<T>(
    Func<MyEntities, DbTransaction, T> function) 
{ 
    using (var ctx = new MyEntities()) 
    { 
     ctx.Connection.Open(); 
     using (var tx = ctx.Connection.BeginTransaction()) 
     { 
      var result = function(ctx, tx); 
      ctx.SaveChanges(); 
      tx.Commit(); 
      return result; 
     } 
    } 
} 

然後,你可以這樣調用。

var result = RunInTransactionAndReturn((ctx,tx) => 
{ 
    // ... do awesome things here 
    return someResult; 
}); 
+0

我會走這(基於方法)的方式。謝謝 – KingKerosin

+0

@KingKerosin你應該知道在lambdas裏面使用ref和我們的參數是不可能的。我會堅持你的IDisposable方法。 – Vlad

+0

@Vlad這裏沒有關於'ref'或'out'參數的信息,恕我直言,你應該避免'ref'和'out',而不是lambda。 – juharr

相關問題