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が小さな実験に追加されたときに始まります(上記のように)。AddFolder関数の最初のAddFileは、トランザクションをDTCにエスカレートします(これは必ず悪いことです)。これは、AddFileが新しいDataContextを初期化し、DBへの2番目の接続を開くためです。

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

4 に答える 4

3

可能な限り、DTC へのエスカレーションは避けるべきであることは間違いありません。あなたの質問を最初に読んだとき、両方のデータ コンテキストで同じ接続文字列を使用しているため、あなたのトランザクションは DTC にエスカレートしないと直感的に言いました。しかし、この記事によると、私は間違っていました。

データ コンテキストのベスト プラクティスについて混乱しているのはあなただけではありません。これをウェブで検索すると、地図のいたるところに答えがあります。あなたの例では、データ コンテキストを AddFile メソッドに渡すことができます。または、フォルダーとファイルがすべて保存されるまでデータ コンテキストの有効期間を維持するクラスに、このデータ アクセスをリファクタリングすることもできます。Rick Strahl は、いくつかのテクニックに関する記事を投稿しました。

それでも、LINQ to SQL に関して私が見た回答のどれも、非常に満足できるものではないようです。ORM を使用してデータ層の管理を回避することを検討したことがありますか? 私はNetTiersを使用して大きな成功を収めましたが、PLINQOについては良いことを耳にします。どちらもCodeSmithを必要としますが、多くの代替手段があります。

于 2009-08-29T20:21:37.840 に答える
1

DataContext をパラメーターとして AddFiles に渡す以外に、ある DataContext の Connection 値を別の DataContext に渡すこともできます。これにより、他の DataContext が同じ接続を持つことが保証されます。

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

于 2009-09-16T04:53:11.583 に答える
0

You don't need to do 2 or more roundtrips for this transaction. I believe LINQ-DataContext is smart to recognize that those files belong to the folder object and will insert the folder row first and files after that (everything in the context of a transaction, e.g. BEGIN TRAN/COMMIT). However you need to do:

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

instead of FolderId. Something like this:

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();
        }
    }
}

To your question regarding DTC: I don't think it's possible to avoid DTC here due to 2 open connections. I believe they made some changes in this area recently, see here, but the scenario described there is a bit different (2 connections opened and closed one after another as opposed to 2 connections open simultaneously).

于 2009-09-13T17:21:32.883 に答える