2009-08-29 17 views
7
public class TestBL 
{ 
    public static void AddFolder(string folderName) 
    { 
     using (var ts = new TransactionScope()) 
     { 
      using (var dc = new TestDataContext()) 
      { 
       var folder = new Folder { FolderName = folderName }; 

       dc.Folders.InsertOnSubmit(folder); 
       dc.SubmitChanges(); 

       AddFile("test1.xyz", folder.Id); 
       AddFile("test2.xyz", folder.Id); 
       AddFile("test3.xyz", folder.Id); 

       dc.SubmitChanges(); 
      } 

      ts.Complete(); 
     } 
    } 

    public static void AddFile(string filename, int folderId) 
    { 
     using (var dc = new TestDataContext()) 
     { 
      dc.Files.InsertOnSubmit(
       new File { Filename = filename, FolderId = folderId }); 

      dc.SubmitChanges(); 
     } 
    } 
} 

これはネストされたDataContext(未テスト)の例です。この問題は、上記のように少しの実験にTransactionScopeが追加されたときに始まります。 AddFile関数の最初のAddFileは、AddFileが新しいDataContextを初期化し、DBへの2番目の接続を開くため、トランザクションをDTC(是非とも悪い)にエスカレートします。BLのネストされたdatacontextを処理する方法は?

  1. DTCの使用が発生しないネストされたDataContextを使用するにはどうすればよいですか?
  2. これはすべて間違っていますか?私は別にDataContextを使用する必要がありますか?
+0

残念ながら、この質問にはそれほど注意を払わなかったし、十分に答えられていないと感じました:( –

答えて

3

可能であれば、DTCへのエスカレートは間違いありません。最初に質問を読むと、両方のデータコンテキストで同じ接続文字列を使用しているため、トランザクションがDTCにエスカレートしないと述べました。しかし、this articleによれば、私は間違っていました。

confusionには、データコンテキストのベストプラクティスを超えているだけではありません。このためにウェブを検索すると、地図上に回答が表示されます。あなたの例では、データコンテキストをAddFileメソッドに渡すことができます。または、このデータアクセスを、フォルダとファイルがすべて保存されるまでデータコンテキストの存続期間を維持するクラスにリファクタリングすることもできます。 Rick Strahlは、いくつかの手法でan articleを投稿しました。

まだ、LINQ to SQLについて見た答えはどれも非常に満足のいくものではありません。 ORMを使用してデータレイヤの管理を避けることを検討しましたか?私はNetTiersを大成功に使用しましたが、PLINQOについては良いことが聞こえます。これらは両方ともCodeSmithが必要ですが、many alternativesがあります。

+0

これは見ている方法の1つです。残念ながら、私はすぐにORMを変更しないので、 –

+0

ORMを変更することは、マイクロソフト社がエンタープライズニーズに適合しない非常に基本的なものを提供するため、賢明な解決策になると思われるので、NHibernateに切り替えました:) –

0

私はこのような状況を処理する方法を考え出しました。

BLエンティティのサンプルの基本クラスは、(エンティティはこのクラスを継承する)

abstract public class TestControllerBase : IDisposable 
{ 
    public TestDataContext CurrentDataContext { get; private set; } 

    protected TestControllerBase() 
    { 
     CurrentDataContext = new TestDataContext(); 
    } 

    protected TestControllerBase(TestDataContext dataContext) 
    { 
     CurrentDataContext = dataContext; 
    } 

    protected void ClearDataContext() 
    { 
     CurrentDataContext.Dispose(); 
     CurrentDataContext = new TestDataContext(); 
    } 

    public void Dispose() 
    { 
     CurrentDataContext.Dispose(); 
    } 
} 

実装コントローラ

public sealed class BLTestController : TestControllerBase 
{ 
    public BLTestController() { } 

    public BLTestController(TestDataContext dataContext) 
     : base(dataContext) { } 

    // The entity functions will be implemented here using CurrentDataContext 
} 

実施コントローラ

の簡単な使用
var testController = new BLTestControllerA(); 

testController.DeleteById(1); 

実装コントローラ(同じDataContextの上の2つのコントローラー)

var testControllerA = new BLTestControllerA(); 
var testControllerB = new BLTestControllerB(testControllerA.CurrentDataContext); 

testControllerA.DeleteById(1); 
testControllerB.DeleteById(1); 

のより複雑な使用私は上記のコードについて、この謎とコメントの解決についてのより多くのアイデアを見てみたいと思います。

0

この取引では、2回以上の往復を行う必要はありません。 LINQ-DataContextは、これらのファイルがフォルダオブジェクトに属していることを認識するのに賢明で、フォルダ行を最初に挿入し、その後にファイルを挿入します(BEGIN TRAN/COMMITなどのトランザクションのすべて)。しかし、あなたがする必要があります:

dc.Files.InsertOnSubmit(
       new File { Filename = filename, Folder = folder }); 

の代わりにFolderId。DTCについてのあなたの質問に

public class TestBL 
{ 
    public static void AddFolder(string folderName) 
    { 
     using (var ts = new TransactionScope()) 
     { 
      using (var dc = new TestDataContext()) 
      { 
       var folder = new Folder { FolderName = folderName }; 

       AddFile(dc, "test1.xyz", folder); 
       AddFile(dc, "test2.xyz", folder); 
       AddFile(dc, "test3.xyz", folder); 

       dc.SubmitChanges(); 
      } 

      ts.Complete(); 
     } 
    } 

    private static void AddFile(DataContext dc, string filename, Folder folder) 
    { 
      dc.Files.InsertOnSubmit(
       new File { Filename = filename, Folder = folder }); 
    } 

    public static void AddFile(string filename, int folderId) 
    { 
     using (var dc = new TestDataContext()) 
     { 
      var folder = new Folder { FolderId = folderId }; 
      dc.Attach(folder, false); 
      AddFile(dc, filename, folder); 

      dc.SubmitChanges(); 
     } 
    } 
} 

:このような何か、私はそれが原因2人の開いている接続に、ここでDTCを回避することが可能だとは思いません。私は彼らが最近このエリアでいくつかの変更を加えたと信じています。hereを参照してください。シナリオには少し違いがあります(同時に2つの接続が同時に開いているのに対し、2つの接続が1つずつ開閉されます)。

+0

リンクここではトランザクションスコープとDTCの関係を完全に説明しましたが、私が尋ねたものとは少し異なります。 –

1

DataContextをパラメータとしてAddFilesに渡すのとは別に、1つのDataContextのConnection値を別のDataContextに渡すこともできます。それは、他のDataContextが同じ接続を持つことを保証します。

各DataContextには、TransactionScopeオブジェクトを使用する代わりに、おそらく設定して渡すことのできるTransactionプロパティもあります。

+0

Connectionプロパティを渡すことはできませんが、何か他のことを意味するかもしれません - コード例を追加できますか? –

+0

@Eran:DataContextオブジェクトには、任意のIDbConnectionオブジェクトを受け入れるオーバーロードされたコンストラクタがあります。したがって、新しいDataContext(OldDataContext.Connection) – rossisdead

関連する問題