2013-07-18 19 views
5

SQLサーバー2008でEF5.0を使用しています。同じサーバーインスタンス上に2つのデータベースがあります。私は両方のデータベースのテーブルを更新し、それらが同じトランザクションになるようにする必要があります。だから、私はTransactionScopeを使用しました。以下はコードです -MS DTCを使用しない同じサーバー上の複数のデータベース(datacontext)

public void Save() 
{ 
     var MSObjectContext = ((IObjectContextAdapter)MSDataContext).ObjectContext; 
     var AWObjectContext = ((IObjectContextAdapter)AwContext).ObjectContext; 

     using (var scope = new TransactionScope(TransactionScopeOption.Required, 
              new TransactionOptions 
               { 
                IsolationLevel = IsolationLevel.ReadUncommitted 
               })) 
     {    
      MSObjectContext.SaveChanges(SaveOptions.DetectChangesBeforeSave); 
      AWObjectContext.SaveChanges(SaveOptions.DetectChangesBeforeSave); 

      scope.Complete(); 
     } 
    } 

上記のコードを使用すると、トランザクションがDTCに昇格されます。インターネットで検索したところ、これは2つの異なる接続文字列/接続のために発生することがわかりました。しかし、私が理解していないのは、(同じサーバー上の)別のデータベースのテーブルを更新するストアドプロシージャをあるデータベースに書き込んでDTCが必要ない場合です。では、なぜEFやTransactionScopeがこれをDTCに宣伝しているのですか?これのために他に何か回避策がありますか?

はプレーンDbConnection Sが事前に

おかげ

サイ

答えて

4

を教えてください、あなたは、どのようなデータベースでも(同じ接続文字列を使用して、同じサーバー上に複数のデータベースのためのDTCエスカレーションを防ぐことができますlike)を開き、手動で開いた接続オブジェクトのデータベースを次のように変更します。

using (var tx = new TransactionScope()) 
{ 
    using (var conn = new SqlConnection(connectStr)) 
    { 
     conn.Open(); 
     new SqlCommand("INSERT INTO atest VALUES (1)", conn).ExecuteNonQuery(); 
    } 
    using (var conn = new SqlConnection(connectStr)) 
    { 
     conn.Open(); 
     conn.ChangeDatabase("OtherDB"); 
     new SqlCommand("INSERT INTO btest VALUES (2)", conn).ExecuteNonQuery(); 
    } 
    tx.Complete(); 
} 

これはconnectStrに異なる値を使用した場合は、DTCにエスカレートしません。

私はEFに慣れていないんだとそれがどのように接続してコンテキストを管理しますが、上記の洞察を使用して、あなたはconn.ChangeDatabase(..)をやって、その後new DbContext(conn, ...)のようなあなたのコンテキストを作成することにより、DTCのエスカレーションを避けることができるかもしれません。

しかし、この変形例のように、でも共有の接続文字列を使用して、できるだけ早くあなたが同時に開く2つの接続を持っているように、DTCが巻き込まれることに注意してください。

using (var tx = new TransactionScope()) 
{ 
    using (var conn = new SqlConnection(mssqldb)) 
    { 
     conn.Open(); 
     new SqlCommand("INSERT INTO atest VALUES (1)", conn).ExecuteNonQuery(); 
     using (var conn2 = new SqlConnection(mssqldb)) 
     { 
      conn2.Open(); 
      conn2.ChangeDatabase("otherdatabase"); 
      new SqlCommand("INSERT INTO btest VALUES (2)", conn2).ExecuteNonQuery(); 
     } 
    } 
    tx.Complete(); 
} 
+0

私がコミットしたいです1つのトランザクションスコープで同じサーバー上の2つの完全に異なるdbs上のトランザクション。私はストアドプロシージャではできますが、EFではできません。あなたの答えをありがとう。 – Sai

+0

私の答えは、格納されたprocsに頼らずに 'TransactionScope'を使ってそれを行う方法を示しています。 'tx.Complete()'行の後に現れる暗黙の 'tx.Dispose()は、2つの異なるデータベースへの両方のINSERTを包含する単一のトランザクションをコミットします。前述したように、EFでは、 'ChangeDatabase()'を手動で呼び出した接続を提供する方法がありますが、コードベースによっては、より結合したコードを生成する可能性があります(TransactionScoepのポイントはコードを切り離す)あなただけが知ることができます。 –

+0

私はDatabaseFirstアプローチを使用していて、dbcontextがエンティティに緊密にバインドされているため、ChangeDatabase()を使用できないと思います。実行時に接続文字列を完全に異なるデータベースに変更すると、エラーがスローされます。 – Sai

関連する問題