2009-08-13 14 views
23

私はADO.NET SqlCommandオブジェクトを作成し、データベース(SQL Server 2005)に保存する項目のリストをループする小さなC#メソッドを継承しました。リファクタリングADO.NET - SqlTransactionとTransactionScope

従来のSqlConnection/SqlCommandアプローチが使用され、すべての動作が確実に行われるように、2つのステップ(古いエントリの削除、新しいエントリの挿入)がADO.NET SqlTransactionにラップされます。

using (SqlConnection _con = new SqlConnection(_connectionString)) 
{ 
    using (SqlTransaction _tran = _con.BeginTransaction()) 
    { 
     try 
     { 
     SqlCommand _deleteOld = new SqlCommand(......., _con); 
     _deleteOld.Transaction = _tran; 
     _deleteOld.Parameters.AddWithValue("@ID", 5); 

     _con.Open(); 

     _deleteOld.ExecuteNonQuery(); 

     SqlCommand _insertCmd = new SqlCommand(......, _con); 
     _insertCmd.Transaction = _tran; 

     // add parameters to _insertCmd 

     foreach (Item item in listOfItem) 
     { 
      _insertCmd.ExecuteNonQuery(); 
     } 

     _tran.Commit(); 
     _con.Close(); 
     } 
     catch (Exception ex) 
     { 
      // log exception 
      _tran.Rollback(); 
      throw; 
     } 
    } 
} 

は今、私は最近、.NETのTransactionScopeクラスについて多くを読んでいる、と私は思っていた、好ましいアプローチは、ここでは何ですか?

using (TransactionScope _scope = new TransactionScope()) 
{ 
    using (SqlConnection _con = new SqlConnection(_connectionString)) 
    { 
    .... 
    } 

    _scope.Complete(); 
} 

何が好きなのですか?また、その理由は何ですか?(読みやすさ、スピード、信頼性)

http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx

を基本的な考え方は、トランザクションスコープがあなたのために、「アンビエントトランザクションコンテキストを」管理するということです。

マルク・

答えて

14

既存のコードをTransactionScopeに切り替えることですぐに何も得られません。柔軟性があるため、将来の開発に使用する必要があります。将来、ADO.NET呼び出し以外のものをトランザクションに含めるほうが簡単になります。

ところで、投稿された例では、SqlCommandのインスタンスはusingブロックになるはずです。

+0

ありがとうJohnさん、ありがとうございます - この例ではusing()ブロック(まだ!)のSqlCommandを持っていません - これは進行中の作業です:-) –

+0

re:SQLCommandを使用中、ありますSQLConnectionのDispose()メソッドはClose()メソッドを呼び出します。したがって、Dispose()はSQLCommandメソッドを呼び出しますか? –

+3

クラスが 'IDisposable'を実装していて、このクラスのインスタンスを作成した場合、そのクラスに対してDisposeを呼び出す必要があります。これを行う最も簡単な方法は、 'using'ブロックを使うことです。私は常に1つを実装するという習慣に入るのが最善だとわかります。 –

9

マイクロソフトは、トランザクション・スコープを使用することをお勧めします。まず、1つのデータベースと対話し、SQLトランザクションを実行した後、データベース番号2と対話し、トランザクションを分散トランザクションに昇格させます。

トランザクションスコープが機能するので、配管ではなくシステムの機能に集中できます。あなたがトランザクション・スコープを使用すると、その範囲内でのすべてがトランザクションによって覆われている

EDIT

。したがって、トランザクションにコマンドを接続するコード行を保存します。これはエラーの可能性があります。たとえば、1000行に1つのチャンスがあった場合、この行を忘れてしまった場合、何行目に行方不明になるかなどです。

EDIT 2

は以下Triynkoにコメントに同意します。ただし、Entity Frameworkを使用すると、EFは自動的に接続を閉じて再オープンし、トランザクションをトランザクションに登録します。接続を物理的に閉じるのではなく、接続プールに解放して新しいものを取得します。新しいものを取得します。同じものでも異なるものでもかまいません。

+0

OK、。それに感謝します。しかし、ADO.NETの組み込みトランザクションの代わりにTransactionScope()を使用するには、すべてをリファクタリングすれば(これは単なるサンプルではない)、何らかのメリットがありますか?その努力が価値があるかどうかを尋ねるだけで、私はそれで何を得るのですか? –

+8

"トランザクションスコープを使用すると、そのスコープ内のすべてがトランザクションによってカバーされます。いいえ、すべてがカバーされていません。スコープに登録されている接続で発行されたコマンドだけがスコープの影響を受けます。スコープで開くと、接続はスコープに自動的に登録されます。それ以外の場合は、既に開いている接続をSqlConnection.EnlistTransactionを呼び出してスコープに手動で追加する必要があります。たとえば、接続を開き、トランザクションスコープを作成すると、トランザクションにはコマンドは含まれません。 – Triynko

+0

@Triynko:対応するMSDNの記事へのあなたのコメントは素晴らしいです! – abatishchev

6

DTC、ファイアウォールなどの設定のように多くの設定が必要なので、トランザクションスコープを使用するだけで問題が発生することがあるので、SqlTransactionの使用を推奨します。

7

私はTransactionScopeを選ぶことをお勧めします。すべてのシナリオで完全に動作するわけではありませんが、記述したシナリオではより良い解決策です。

私の推論:トランザクションで

  1. 入隊は、例外が発生した場合に
  2. 自動トランザクションのロールバックが一緒に自動

です、結果は少し少ないコードであり、一般にシステムが私のためにいくつかの詳細を処理しているので、よりロバストな設計。それは私が忘れてはならないことの一つです。

さらに、トランスペアレントトランザクション登録は、DALに多数のネストされたメソッドがある場合に特に便利です。ただし、トランザクションを誤ってDTCを必要とする分散トランザクションにしないように注意する必要があります。同じDBを指していても、複数のSqlConnectionを使用した場合に発生する可能性があります。

2

は[OK]を、多分これのために遅すぎる...しかし、私は、今より良い写真を持っているのでとにかく、私は私の現在に多くの困難を持った後

...興味のある方のためにそれを書き留めますSqlTransaction私はTransactionScopeを好むように変更する可能性のあるアプローチ... TransactionScopeの主な利点はです。それはビジネスレイヤーで非常に簡単に使用することができます

2

また遅れています...ネストされたトランザクションをデータベースがサポートしていなくても、ビジネスレイヤーに「入れ子になった」トランザクションを簡単に配置できます。 .NETはネストを制御し、1つのデータベーストランザクション(少なくともSQL Server 2008+の場合)を使用して終了します。これにより、大規模なトランザクションの一環として、データアクセスコードを元のインテントの外で再利用する方がはるかに簡単になります。