2

次のような(非常に単純化された)システム(少しDDDのような)でLinq to SQLの使用を開始しました。

public class SomeEntity // Imagine this is a fully mapped linq2sql class.
{
    public Guid SomeEntityId { get; set; }
    public AnotherEntity Relation { get; set; }
}

public class AnotherEntity // Imagine this is a fully mapped linq2sql class.
{
    public Guid AnotherEntityId { get; set; }
}

public interface IRepository<TId, TEntity>
{
    Entity Get(TId id);
}

public class SomeEntityRepository : IRepository<Guid, SomeEntity>
{
    public SomeEntity Get(Guid id)
    {
        SomeEntity someEntity = null;
        using (DataContext context = new DataContext())
        {
            someEntity = (
                from e in context.SomeEntity
                where e.SomeEntityId == id
                select e).SingleOrDefault<SomeEntity>();
        }

        return someEntity;
    }
}

さて、問題が発生しました。このように SomeEntityRepository を使用しようとすると

public static class Program
{
    public static void Main(string[] args)
    {
        IRepository<Guid, SomeEntity> someEntityRepository = new SomeEntityRepository();
        SomeEntity someEntity = someEntityRepository.Get(new Guid("98011F24-6A3D-4f42-8567-4BEF07117F59"));
        Console.WriteLine(someEntity.SomeEntityId);
        Console.WriteLine(someEntity.Relation.AnotherEntityId);
    }
 }

プログラムが最後の WriteLine に到達するまで、すべてがうまく機能ObjectDisposedExceptionします。

実際の問題はわかりますが、どうすればこれを解決できますか? いくつかの解決策があると思いますが、これまでに考えたもののどれも私の状況には適していません。

  • リポジトリ パターンから離れて、作業のアトミックな部分ごとに新しい DataContext を使用します。
    • 私は本当にこれをしたくありません。理由は、アプリがリポジトリを意識したくないからです。もう 1 つは、linq2sql を COM で可視化するのは良いことだとは思わないということです。
    • また、私がcontext.SubmitChanges()意図したよりも多くのことをコミットする可能性が高いと思います。
  • 関連する要素をフェッチするための DataLoadOptions を指定します。
    • 場合によっては、ビジネス ロジック レイヤーがいくつかのエンティティで応答するようにしたいので、どのサブ プロパティを使用する必要があるかわかりません。
  • すべてのプロパティの遅延読み込み/遅延読み込みを無効にします。
    • かなりの数のテーブルがあり、それらは強くリンクされているため、オプションではありません。これにより、多くの不要なトラフィックとデータベースの負荷が発生する可能性があります。
  • インターネット上のいくつかの投稿では、.Single() を使用すると役立つはずです。
    • どうやらそうではありません...

この悲惨さを解決する方法はありますか?

ところで: Linq t0 SQL を使用することにしたのは、それが比較的軽量な ORM ソリューションであり、.NET フレームワークと Visual Studio に含まれているためです。.NET Entity Framework がこのパターンにより適している場合は、それに切り替えるオプションになる可能性があります。(実装はまだそこまで進んでいません。)

4

5 に答える 5

4

Rick Strahlは、DataContextライフサイクル管理に関するすばらしい記事をここに持っています:http ://www.west-wind.com/weblog/posts/246222.aspx 。

基本的に、アトミックアクションアプローチは理論的には優れていますが、データオブジェクトの変更を追跡(および子をフェッチ)できるようにするには、DataContextを維持する必要があります。

参照:Linq toSQLDataContextおよびLINQtoSQLの複数/単一インスタンス-DataContextはどこにありますか?

于 2008-11-03T19:10:09.887 に答える
1

次のいずれかを行う必要があります。

1) 使用するデータをまだ完全に決定していないため、コンテキストを開いたままにします (別名、遅延読み込み)。

または 2) 他のプロパティが必要になることがわかっている場合は、初期ロードでより多くのデータをプルします。

後者の説明:こちら

于 2008-11-03T19:53:16.070 に答える
1

原子単位の作業を行う場合、リポジトリを放棄する必要があるかどうかはわかりません。私は両方を使用しますが、(タイムスタンプやその他の必要な規則を使用せずに) レイヤーで機能しないため、オプティミスティック同時実行チェックを破棄することは認めます。私が最終的に得たのは、DataContext を使用し、完了したら破棄するリポジトリです。

これは関係のない Silverlight の例の一部ですが、最初の 3 つの部分は、使い捨ての LINQ to SQL コンテキストでリポジトリ パターンを使用する方法を示しています。FWIW: http://www.dimebrain.com/2008/09/linq-wcf -silver.html

于 2008-11-03T20:09:43.340 に答える
0

関連する要素をフェッチするための DataLoadOptions を指定します。場合によっては、ビジネス ロジック レイヤーがいくつかのエンティティで応答するようにしたいので、どのサブ プロパティを使用する必要があるかわかりません。

.Relation プロパティを使用するために必要な結合が呼び出し元に付与されている場合、呼び出し元は DataLoadOptions を指定することもできます。

DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Entity>(e => e.Relation);
SomeEntity someEntity = someEntityRepository
  .Get(new Guid("98011F24-6A3D-4f42-8567-4BEF07117F59"),
  loadOptions);

///

using (DataContext context = new DataContext())
{
  context.LoadOptions = loadOptions;
于 2008-11-03T18:49:28.900 に答える
0

これは私がしていることであり、これまでのところ非常にうまく機能しています。

1) DataContext をリポジトリのメンバー変数にします。はい、これは、リポジトリが IDisposable を実装し、開いたままにしないようにする必要があることを意味します...おそらく、やらなければならないことを避けたいと思うかもしれませんが、不便だとは思いませんでした。

2) 次のようにいくつかのメソッドをリポジトリに追加します。

public SomeEntityRepository WithSomethingElseTheCallerMightNeed()
{
 dlo.LoadWith<SomeEntity>(se => se.RelatedEntities);
 return this; //so you can do method chaining
}

次に、呼び出し元は次のようになります。

SomeEntity someEntity = someEntityRepository.WithSomethingElseTheCallerMightNeed().Get(new Guid("98011F24-6A3D-4f42-8567-4BEF07117F59"));

リポジトリがデータベースにヒットしたときに、それらのヘルパー メソッドで指定されたデータ ロード オプションが使用されることを確認する必要があります。私の場合、「dlo」はメンバー変数として保持され、データベースにヒットする直前に設定されます。

于 2009-09-03T23:28:18.503 に答える