ADO.NET Entity Frameworkのトランザクションに関するMSDTCの問題
-
05-07-2019 - |
質問
現在のプロジェクトでは、ADO.NET Entity Frameworkをアプリケーションのデータレイヤーとして使用しています。データベースには多くの作業が必要なため、トランザクションで実行する必要があるタスクがいくつかあります。これらのタスクを囲むために TransactionScope を使用しています。
using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
// Do something...
transactionScope.Complete();
}
TransactionScopeを使用するとすぐに問題が発生します例外が発生します:
System.Data.EntityException:基になるプロバイダーは、Openで失敗しました。 ---> System.Transactions.TransactionManagerCommunicationException:基になるトランザクションマネージャーとの通信に失敗しました。 ---> System.Runtime.InteropServices.COMException(0x80004005):COMコンポーネントの呼び出しからエラーHRESULT E_FAILが返されました。
このエラーは、 MSDTC (Microsoft分散トランザクションコーディネーター)。 MSDTCのセキュリティ構成を変更すると、別の例外がスローされます:
System.Data.EntityException:基になるプロバイダーは、Openで失敗しました。 ---> System.Transactions.TransactionManagerCommunicationException:分散トランザクションマネージャー(MSDTC)のネットワークアクセスが無効になっています。コンポーネントサービス管理ツールを使用して、MSDTCのセキュリティ構成でネットワークアクセスのDTCを有効にしてください。
ただし、MSDTCが構成されている場合、 TransactionScope エラーが発生します。 誰かがここで間違っていることを知っていますか?
解決 8
うーん、 TransactionScopeOptionを変更すると動作するようですから" Suppress":
using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.Suppress))
{
...
}
誰もがその理由を知っていますか?
他のヒント
デフォルトでは、MSDTCのネットワークアクセスは無効になっています。動作させるには
に移動する必要がありますコントロールパネル->行政 ツール->コンポーネントサービス->コンポーネント サービス->コンピューター->マイコンピューター->右 クリック->プロパティ-> MSDTC->セキュリティ 設定
次のチェックボックスをオンにします。ネットワークDTCアクセス、インバウンドを許可、アウトバウンドを許可。環境に応じて認証を選択する必要があります。 もご覧ください。分散トランザクションをデバッグするDTCPing ツール。ショートカットを提供するには、レジストリを変更する必要がある場合があります。
HKLM \ Software \ Policies \ Microsoft \ Windows NT \ RPCRestrictRemoteClients = 0 HKLM \ Software \ Policies \ Microsoft \ Windows NT \ RPCEnableAuthEpResolution = 1
すべてを起動して実行します。
はい、アンビエントトランザクションを抑制または無視して新しいローカルトランザクションを作成するように指示しているため、Supressを使用して動作します。トランザクションはローカルであるため、分散トランザクションではないため、MSDTCは使用しませんが、Suppressは使用せず、代わりにRequiredを使用する必要があります。
これは、コードブロックを入力するときに現在有効な可能性のあるトランザクションを抑制しているため、外側の「アンビエント」がコードブロックによって更新されてもロールバックしないことを意味します。トランザクションはロールバックを決定します。
これは、同様の問題を解決するために使用した記事です。
これは、基本的に Nikolay Rの回答の補遺です。彼はすでに記事にリストされている提案のいくつかをカバーしました。
注:この記事はBiztalkドキュメントの一部ですが、MSDTCを使用するあらゆるものに適用できます。
"トランザクションでEntity Frameworkを使用している場合、Entity Frameworkは各データベース呼び出しとの接続を自動的に開いたり閉じたりします。したがって、トランザクションを使用する場合、トランザクションを複数の接続に分散しようとしています。これはMSDTCに昇格します。"
データベースコンテキストをトランザクションの呼び出し先クラスまたは関数に渡すことができます。
これがあなたの答えかもしれません: MSSQLエラー「基礎となるプロバイダーはオープンに失敗しました」
トランザクションを抑制することは、失敗する可能性のあるコードを実行したいが、その失敗のためにトランザクションを中止したくない場合に便利です。
自問する必要がある質問は次のとおりです。 transactionScopeで複数の永続リソースにアクセスしていますか?つまり、複数のDBへの接続を開いていますか?
複数の永続リソースにアクセスすると、トランザクションがDTCにエスカレートされるため、これは重要な質問です。
単一フェーズの通知をサポートする少なくとも2つの永続的なリソースがトランザクションに参加します。たとえば、単一の接続に参加しても、トランザクションは昇格されません。ただし、データベースへの2番目の接続を開いてデータベースを登録すると、System.Transactionsインフラストラクチャはそれがトランザクション内の2番目の永続リソースであることを検出し、それをMSDTCトランザクションにエスカレートします。 ソース: MSDN
その場合、トランザクションスコープを正しくネストすることで問題を解決できます。例:
//Create rootScope
using(TransactionScope rootScope = new TransactionScope())
{
using(TransactionScope scope2 = new
TransactionScope(TransactionScopeOption.Required))
{
//Do work on DB1
...
//Complete this ambient transaction
scope2.Complete();
}
using(TransactionScope scope3 = new
TransactionScope(TransactionScopeOption.Required))
{
//Do work on DB2
...
//Complete this ambient transaction
scope3.Complete();
}
//Complete rootScope
//The whole transaction will only be committed if you call
//Complete on the rootScope
rootScope.Complete();
}
MSDN 。
この回答が将来の人々に役立つことを願っています。
Distributed Transaction Coordinatorサービスが開始されていない場合、Entityフレームワークはデータベースに接続できません。 分散トランザクションコーディネーターを開いて起動します
サービス->分散トランザクションコーディネーター