dapper.netでトランザクションを使用する方法?


106

複数のテーブルで複数の挿入ステートメントを実行したいと思います。私はdapper.netを使用しています。dapper.netでトランザクションを処理する方法がわかりません。

トランザクションの使用方法に関するアイデアをdapper.netと共有してください。

回答:


107

ここにコードスニペット:

using System.Transactions;    
....    
using (var transactionScope = new TransactionScope())
{
    DoYourDapperWork();
    transactionScope.Complete();
}

System.Transactionsデフォルトでは参照されないため、アセンブリへの参照を追加する必要があることに注意してください。


7
エラー時に明示的にロールバックする必要がありますか、それともSystem.Transactionsが自動的に処理しますか?
Norbert Norbertson 2017年

6
@NorbertNorbertson Dispose()メソッドで自動的に実行します。Complete()呼び出されていない場合、トランザクションはロールバックされます。
the_joric 2017年

4
別の回答のために言及する価値がある(stackoverflow.com/a/20047975/47672):TransctionScopeこの回答を選択する場合は、usingブロック内で接続を開く必要があります。
0x49D1

2
参照(stackoverflow.com/a/20047975/444469)-DoYouDapperWork(実行、クエリなど...)には、パラメーターでトランザクションが必要です。
Matthieu

問題がある場合、ロールバックは自動的に呼び出されますか?
ガンダルフ

91

接続から直接トランザクションを取得することにより、より直感的なアプローチを使用することを選びました。

// This called method will get a connection, and open it if it's not yet open.
using (var connection = GetOpenConnection())
using (var transaction = connection.BeginTransaction())
{
    connection.Execute(
        "INSERT INTO data(Foo, Bar) values (@Foo, @Bar);", listOf5000Items, transaction);
    transaction.Commit();
}

@ANeves:ええと、私たちはおそらく別のDapperフレームワークを使用しています。これは、次のフレームワークがあるためです:github.com/StackExchange/dapper-dot-net
andrecarlucci '28

25
.begintransactionの前にconnection.open()を呼び出す必要があります
タイムレス

接続は、transactionscope内で接続を開かない限り、transactionscopeに自動的に登録されません。GetOpenConnectionがなんとなくトランザクションスコープ内で魔法のように自分自身を開いた場合、コードがどのように機能するかはわかりませんが、それができないことに賭けます
Erik Bergstedt

@ErikBergstedt、私たちがそれを呼び出したのみ接続を開く必要があると言っていますか?その場合、この拡張メソッドはトランザクションの誤った使用を促進します。(IMOは、「接続が既に開いていると、トランザクションを開くことができません」をスローする必要があります。).BeginTransaction()
ANeves 2015年

2
Executeこれは必須なので、トランザクションをパラメータとして含めるのが適切です。
Arve Systad 2017年

19

TransactionScopeDapperはADO.NETコマンドだけを実行するので、使用できるはずです。

using (var scope = new TransactionScope())
{
   // insert
   // insert
   scope.Complete();
}

8

すべてのテーブルが単一のデータベースにあることを考えると、私はTransactionScopeここのいくつかの回答で提案されている解決策に同意しません。この回答を参照してください。

  1. TransactionScope通常、分散トランザクションに使用されます。異なるデータベースにまたがるトランザクションは、異なるシステム上にある可能性があります。これには、オペレーティングシステムとSQL Serverでいくつかの構成が必要です。この構成がないと機能しません。すべてのクエリがデータベースの単一インスタンスに対するものである場合、これは推奨されません。
    ただし、単一のデータベースの場合、これは、制御できないトランザクションにコードを含める必要がある場合に役立ちます。単一のデータベースでは、特別な構成も必要ありません。

  2. connection.BeginTransaction単一のデータベースに対してトランザクション(C#、VB.NETなど)を実装するADO.NET構文です。これは複数のデータベースでは機能しません。

だから、connection.BeginTransaction()行くためのより良い方法です。

トランザクションを処理するより良い方法は、この回答で説明されているようにUnitOfWorkを実装することです。


4
TransactionScopeを利用するために複数のデータベースは必要ありません。特に有用なのは、それが周囲環境であることです。所有していない、または変更できないコードをトランザクションでラップするのに最適です。たとえば、ロールバックしたい場所でデータベース呼び出しを行うユニット/統合テストコードを実行するときに、これを使用して大きな効果を得ることができます。TransactionScopeをフロートさせ、コードをテストし、テストのクリーンアップ中に破棄するだけです。
ラリー・スミス、

3
@LarrySmith:同意する; しかし、問題はこれについては何もありません。OPは、1つのトランザクションで複数のテーブルに挿入することを望んでいると述べています。受け入れられたものを含むいくつかの答えは、TransactionScopeOPが望むものに対して非効率的な使用を提案します。TransactionScope多くの場合、これは優れたツールです。これではありません。
Amit Joshi

5

ダニエルの答えは期待通りに機能しました。完全を期すために、トランザクションスコープとdapperを使用したコミットとロールバックを示すスニペットを次に示します。

using System.Transactions;
    // _sqlConnection has been opened elsewhere in preceeding code 
    using (var transactionScope = new TransactionScope())
    {
        try
        {
            long result = _sqlConnection.ExecuteScalar<long>(sqlString, new {Param1 = 1, Param2 = "string"});

            transactionScope.Complete();
        }
        catch (Exception exception)
        {
            // Logger initialized elsewhere in code
            _logger.Error(exception, $"Error encountered whilst executing  SQL: {sqlString}, Message: {exception.Message}")

            // re-throw to let the caller know
            throw;
        }
    } // This is where Dispose is called 

2
@usrは個人の好みに応じて変わります。私は何かが最初にうまくいかなかったことを知り、ログステートメントをゴミとして見ないようにします。また、私の答えは、dapperでトランザクションを使用する1つの方法を示すことによって、依然として価値を
宣伝

@CodeNaked、最初に、あなたはそこに間違った順序を持っています。例外がある場合、catchブロックが最初にヒットし、次に使用のスコープが終了します。次に、この回答と参照されているMSDNドキュメントを見てください。stackoverflow.com/ a / 5306896/190476を2回呼び出して破棄しても害はありません。適切に設計されたオブジェクトは2番目の呼び出しを無視します。反対票は正当化されません!
Sudhanshu Mishra

@dotnetguy- Dispose最初に呼び出されるメソッドと2番目に呼び出されるメソッドを通信しようとはしていませんでした。「処分を2回呼び出すことは害がない」という点に関しては、それは大きな仮定です。ドキュメントと実際の実装が一致しないことがよくあることを知りました。しかし、Microsoftの言葉が必要な場合は、msdn.microsoft.com
en

3
だから、コード分析の警告はあなたが反対票を投じる理由ですか?それは答えを間違ったり誤解を招くようなものではありません-それは反対投票が適切なときです。機能を維持しながら、答えを編集してより良い解決策を提案してみませんか?スタックオーバーフローは、支援と建設的な批判に関するものです。
Sudhanshu Mishra
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.