多くのDALコードでは、トランザクションにTransactionScopeが使用されています。それは素晴らしいですが、SQLCLRプロシージャの内部からこのDALコードを使用すると問題が発生します。トランザクションは私が望まないものをMSDTCにエスカレートされます。 CLR手順MSDTCへのエスカレーションなしでSQLCLRでTransactionScopeを使用する方法
BEGIN TRANSACTION
exec dbo.ClrWithTrans "select * from sys.tables";
exec dbo.ClrWithScope "select * from sys.tables"; /* <- DOES NOT WORK! */
ROLLBACK TRANSACTION
CLR実装
[SqlProcedure] public static void ClrWithScope(string cmdText) { /* escalates to MSDTC when a transaction is already open */ using (var scope = new TransactionScope()) { using (var connection = new SqlConnection("context connection=true;")) { connection.Open(); using (var cmd = new SqlCommand(cmdText, connection)) { SqlContext.Pipe.ExecuteAndSend(cmd); } } scope.Complete(); } } [SqlProcedure] public static void ClrWithTrans(string cmdText) { /* works as expected (without MSDTC escalation) */ using (var connection = new SqlConnection("context connection=true;")) { connection.Open(); using (var tx = connection.BeginTransaction()) { using (var cmd = new SqlCommand(cmdText, connection, tx)) { SqlContext.Pipe.ExecuteAndSend(cmd); tx.Commit(); } } } }
SQLスクリプト:
問題を簡単に再現できます"TRANSACTIONをBEGIN" 文WIHTOUT
エラー
Msg 6549, Level 16, State 1, Procedure ClrWithScope, Line 0 A .NET Framework error occurred during execution of user defined routine or aggregate 'clrClrWithScope': System.Transactions.TransactionAbortedException: Die Transaktion wurde abgebrochen. ---> System.Transactions.TransactionPromotionException: MSDTC on server 'BLABLA' is unavailable. ---> System.Data.SqlClient.SqlException: MSDTC on server 'BLABLA' is unavailable. System.Data.SqlClient.SqlException: bei System.Data.SqlServer.Internal.StandardEventSink.HandleErrors() bei System.Data.SqlServer.Internal.ClrLevelContext.SuperiorTransaction.Promote() System.Transactions.TransactionPromotionException: bei System.Data.SqlServer.Internal.ClrLevelContext.SuperiorTransaction.Promote() bei System.Transactions.TransactionStatePSPEOperation.PSPEPromote(InternalTransaction tx) bei System.Transactions.TransactionStateDelegatedBase.EnterState(InternalTransaction tx) System.Transactions.TransactionAbortedException: bei System.Transactions.TransactionStateAborted.CreateAbortingClone(InternalTransaction tx) bei System.Transactions.DependentTransaction..ctor(IsolationLevel isoLevel, InternalTransaction internalTransaction, Boolean blocking) bei System.Transactions.Transaction.DependentClone(DependentCloneOption cloneOption) bei System.Transactions.TransactionScope.SetCurrent(Transaction newCurrent) bei System.Transactions.TransactionScope.PushScope() bei System.Transactions.TransactionScope..ctor(TransactionScopeOption scopeOption) bei Giag.Silo.Data.SqlClr.ClrWithScope(String cmdText) . User transaction, if any, will be rolled back.
、dbo.ClrWithScopeコールがOKに動作します。私は、SQLServerによって開始されたトランザクションは.Net Frameworkに参加している間は考慮されないと考えています。
これを解決する方法はありますか。手動でSqlTransactionを作成し、このトランザクションを使用するようにTransactionScopeを作成することが考えられますが、これを行う方法はわかりません。もう1つの解決策は、DALコードのすべてで特殊なケースを作ることです(実装するのは面白くない)。
アイデア?
は 'Scope' – Magnus
@Magnus周り' Connection'を入れてみてくださいしかし、それは(自動的に)のTransactionScopeの全体の目的で周囲のトランザクションへの接続を参加しない、それはないですか? –
Christian.Kが正しいです。 DALコードは、TransactionScopeとSqlConnectionを多く使用しています。もちろん、DALでコードベース全体を書き換えることは可能ですが、それはうまくありません。 – sschoenb