1

ADO.NET Entity Framework に苦労しています。これは私のER図です:

---------------------        -----------------        ---------------
| GrandParentEntity |<-------| ParentEntity  |<-------| ChildEntity |
+-------------------+ 1    N +---------------+ 1    N +-------------+
| Id                |        | Id            |        | Id          |
---------------------        | GrandParentFk |        | ParentFk    |
                             -----------------        ---------------

オブジェクト コンテキストの有効期間について質問があります。次のようにデータをリクエストするとします。

public static List<MyParentEntity> GetMyParentEntity()
{
    using (var context = new MyObjectContext(blablabla...))
    {
        var resultSet = from e in context.MyParentEntitySet select e;
        return resultSet.ToList();
    }
}

すべての親エンティティのリストを取得します。しばらくして (数時間?)、ユーザーはどれを検査するかを決定します。(その間、エンティティ オブジェクトはアプリケーションのいくつかの層を通過しました。) 次に、レコードのすべての詳細をロードする必要があります。

public static void LoadChildren(MyParentEntity pEntity)
{
    using (var context = new MyObjectContext(blablabla...))
    {
        pEntity.GranParentEntityReference.Load();
        pEntity.ChildEntites.Load();
    }
}

これは、MyParentEntity オブジェクトがそれを作成したオブジェクト コンテキストへの接続を失ったため、ObjectDisposedException につながります。これを処理するには、いくつかの可能性があります。

1) MyObjectContext の同じインスタンスを常に使用でき、それを閉じることはありません。これは大量のメモリの浪費につながります。

2)「(コンテキスト)を使用する」ブロックを離れるたびに、すべてのエンティティオブジェクト(およびその子エンティティと親エンティティ)を手動で Detach() できます。そして、新しい「using(context)」ブロックに入るたびにそれらを Attach() できます。多くの努力につながります。(私の意見では、フレームワークは労力を増やすのではなく減らすべきです。)

3)新しい「using(context)」ブロックに入るたびに、各エンティティをリロードしてから破棄します。SQL Server の (不必要な) 負荷が増加し、メモリも浪費します。

4) アプリケーションの起動時に、すべての詳細、すべての参照、すべての参照のすべての参照、およびそれらの参照の参照をロードできます。(議論はありません、これは本当にばかげています!)

5) ... (オプションを忘れましたか?)

ここで、あなたへの大きな質問: どの方法を選択すればよいですか? 私が見ていない別の方法はありますか?それとも、フレームワークの精神を完全に誤解していましたか?

前もって感謝します

更新: Windows フォーム アプリケーションです。

4

3 に答える 3

2

私は2番目のオプションを行います。すべてのエンティティをデタッチする必要はありません。クエリを NoTracking に設定すると、エンティティは最初からコンテキストにアタッチされず、関係が失われることはありません (ロードされている場合)。

 public static List<MyParentEntity> GetMyParentEntity(){
using (var context = new MyObjectContext(blablabla...))
{
    var resultSet = from e in context.MyParentEntitySet select e;
    ((ObjectQuery)resultSet).MergeOption = MergeOption.NoTracking;
    return resultSet.ToList();
}}

次に、アプリケーションが Web ベースか Windows ベースかという問題があります。Web ベースの場合は、リクエストごとにコンテキストが作成されるシングルトン パターンを使用することをお勧めします。

 public class Singleton
 {
    public static YourContext _context;
    public static YourContext Context
    {
        get
        {
            //We are in a web app, use a request scope
            if (HttpContext.Current != null)
            {
                YourContext current_context = (YourContext)HttpContext.Current.Items["_YourContext"];

                if (current_context == null)
                {
                    current_context = new YourContext();
                    HttpContext.Current.Items.Add("_YourContext", current_context);                    
                }
                return current_context;
            }
            else
            {
                if (_context == null)
                    _context = new YourContext();

                return _context;
            }
        }
    }
}

Web アプリでない場合のベスト プラクティスをどうすればよいかわからないため、静的フィールドに配置するのは得策ではないかもしれません。このフレームワークは少し複雑で、そのしくみを詳しく読むことで理解が深まり、このような状況を避けることができます。Julia Lerman の本 Programming Entity Framework, 1st Edition を使用しました。

于 2009-09-08T12:30:48.197 に答える
0

私はオプション5を提案します:

public static MyParentEntity LoadChildren(MyParentEntity pEntity)
{ 
      using (var context = new MyObjectContext(...))
      {
           pEntity = (from e in context.MyParentEntitySet.Include("GranParentEntityReference").Include("ChildEntites") 
                      where e.Id == pEntity.Id
                      select e).FirstOrDefault();
        return pEntity;
      }
}

2つの.Includeは、クエリにそれらが含まれていることを確認するためにここにあります(そして、私がそれほど前にそれを発見したためです)。

linqpadでテストしましたが、現在は機能していますが、機能しない場合(とにかくそのケースに遭遇したことはありません)、非常に大量のデータについて話している場合を除いて、オプション1の方が適切な解決策のようです。エンドユーザー端末のスペックが低い可能性があること。

完全に無関係なメモでは、最初のクエリを単純化できます(そのクエリにそれ以上何もない場合):

using (var context = new MyObjectContext(blablabla...))
{
    var resultSet = context.MyParentEntitySet.ToList();
    return resultSet;
}

(しかし、それはあなたの問題を解決しません)

于 2009-09-09T06:52:03.450 に答える
0

そこで、Julia Lerman の「Programming Entity Framework」をほぼ 1 日中読んだ後、ようやくヒントを見つけました。第 20 章で、彼女は「長時間実行オブジェクト コンテキストの使用」について語っています。これは、オプション 1 と 3 を部分的にカバーします。ユーザーが同じビューにとどまっている限り、コンテキストは開いたままになります。コンテキストは、UI が新しいビューに切り替わるたびに破棄されます。新しいビューでは、新しいコンテキストが作成され、最近のビューから再利用されたすべてのエンティティを再読み込みする必要があります。

私にとっては多くのリファクタリングを意味しますが、私はこのソリューションで暮らすことができます...

于 2009-09-09T15:43:22.540 に答える