4

SqlTransaction を使用する次のコードがあります。Dispose を catch で呼び出して、finally ブロックしました。しかし、Dispose() を呼び出す前に、既に破棄されているかどうかを確認していません。Dispose() を呼び出す前に、SqlTransaction が既に破棄されているかどうかを確認するにはどうすればよいでしょうか?

MSDN:SqlTransaction.Dispose Methodを参照しました。しかし、それは私の質問をカバーしていません。

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqltransaction.dispose(v=vs.100).aspxも参照

注: が よりTransactionScopeも優れていることは既にわかっていSqlTransactionます。しかし、私は SqlTransaction の破棄を理解しようとしています。

コード

 using (SqlConnection connection = new SqlConnection(connectionString))
        {
            connection.Open();

            SqlTransaction transaction = null;

            try
            {
                transaction = connection.BeginTransaction();

                sessionID = GetSessionIDForAssociate(connection, empID, transaction);
                //Other code

                //Commit
                transaction.Commit();
            }
            catch
            {
                //Rollback
                if (transaction != null)
                {
                    transaction.Rollback();
                    transaction.Dispose();
                }

                //Throw exception
                throw;
            }
            finally
            {
                if (transaction != null)
                {
                    transaction.Dispose();
                }
            }
4

4 に答える 4

8

Dispose()を呼び出す前に、SqlTransactionがすでに破棄されているかどうかを確認するにはどうすればよいですか?

あなたはする必要はありません。disposeを2回呼び出しても、問題は発生しません。

破棄-MSDN

オブジェクトのDisposeメソッドが複数回呼び出された場合、オブジェクトは最初の呼び出し以降のすべての呼び出しを無視する必要があります。Disposeメソッドが複数回呼び出された場合、オブジェクトは例外をスローしてはなりません。Dispose以外のインスタンスメソッドは、リソースがすでに破棄されている場合にObjectDisposedExceptionをスローする可能性があります。

ただし、Disposeを1回だけ呼び出したい場合は、ブールフラグを使用してトランザクションが破棄されるタイミングを設定するか、nullに設定できます。または、ブロックが常に呼び出されるため、catchブロック内で破棄する呼び出しを削除します。finally

SqlTransactionはIDisposableを実装しているため、ブロックを使用して使用する方が適切です。何かのようなもの:

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();

    using (SqlTransaction transaction = connection.BeginTransaction())
    {
        try
        {
            sessionID = GetSessionIDForAssociate(connection, empID, transaction);
            //Other code

            //Commit
            transaction.Commit();
        }
        catch
        {
            //Rollback
            if (transaction != null)
            {
                transaction.Rollback();
            }

            //Throw exception
            throw;
        }
    }
}

ブロックの使用はブロックのように機能try/finallyするため、(例外が発生した場合でも)完了時にトランザクションを確実に破棄します。したがって、手動でを呼び出す必要はありませんDispose

于 2013-01-21T12:42:35.227 に答える
2

すでに破棄されているかどうかを確認する必要があるのはなぜですか? ブロックDisposeからの呼び出しを単純に省略することで、2 回の呼び出しを避けることができます。catch

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();

    SqlTransaction transaction = null;

    try
    {
        transaction = connection.BeginTransaction();

        sessionID = GetSessionIDForAssociate(connection, empID, transaction);
        //Other code

        //Commit
        transaction.Commit();
    }
    catch
    {
        //Rollback
        if (transaction != null)
        {
            // No need to dispose here - finally is always called
            transaction.Rollback();
        }

        //Throw exception
        throw;
    }
    finally
    {
        if (transaction != null)
        {
            // Always called, so no need to dispose elsewhere.
            transaction.Dispose();
        }
    }
于 2013-01-21T12:40:36.087 に答える
2

transaction=nulldispose を呼び出した後に追加すると、既存のテストが機能します。

于 2013-01-21T12:38:33.373 に答える
2

.Dispose()catch ブロックから呼び出しを削除します。最終的には常に実行されるため、この方法ではトランザクションを 2 回破棄しようとしています。

「すでに破棄されているかどうかをどうやって知ることができますか」という回答はありませんが、おそらく問題は解決します。

于 2013-01-21T12:41:51.363 に答える