web-dev-qa-db-ja.com

EF6のEager、遅延および明示的な読み込み

私はこれを読みました tutorial とこれ article ですが、各ローディングタイプの使用法を正確に理解していません。

説明する

私はこのPOCOを持っています:

public partial class dpc_gestion
{
    public dpc_gestion()
    {
        this.ass_reunion_participant = new HashSet<ass_reunion_participant>();
        this.dpc_participant = new HashSet<dpc_participant>();
        this.dpc_reunion = new HashSet<dpc_reunion>();
    }

    public int dpc_id_pk { get; set; }
    public Nullable<int> dpc_id_gdp_fk { get; set; }
    public Nullable<int> dpc_id_theme { get; set; }
    public int dpc_id_animateur_fk { get; set; }
    public Nullable<System.DateTime> dpc_date_creation { get; set; }
    public Nullable<System.DateTime> dpc_date_fin { get; set; }
    public Nullable<System.DateTime> dpc_date_engag_anim { get; set; }
    public Nullable<bool> dpc_flg_let_engag_anim { get; set; }
    public Nullable<bool> dpc_flg_fsoins_anim { get; set; }
    public virtual ICollection<ass_reunion_participant> ass_reunion_participant { get; set; }
    public virtual theme_dpc theme_dpc { get; set; }
    public virtual gdp_groupe_de_pair gdp_groupe_de_pair { get; set; }
    public virtual ICollection<dpc_participant> dpc_participant { get; set; }
    public virtual ICollection<dpc_reunion> dpc_reunion { get; set; }
}

私はこれを理解しました:

  1. 遅延読み込みの場合:読み込みが遅延しているため、dbset dpc_gestionすべてのナビゲーションプロパティを呼び出すとロードされません。このタイプのロードは、パフォーマンスと応答性において最高です。デフォルトで有効になっています。再度有効にするには、次のように設定する必要があります。

    context.Configuration.ProxyCreationEnabled = true;    
    context.Configuration.LazyLoadingEnabled = true;
    
  2. 積極的な読み込みの場合怠zyではありません:dpc_gestionを読み込むと、すべてのナビゲーションプロパティが読み込まれます。ナビゲーションプロパティは、includeメソッドを使用してロードできます。この読み込みタイプを有効にするには:

    context.Configuration.LazyLoadingEnabled = false;
    
  3. 明示的な読み込みの場合これは、積極的な読み込みに似ていますが、Loadの代わりにincludeメソッドを使用します。

だから私は知りたい:

  1. この小さな履歴書が本当なら?
  2. それが本当なら、熱心な読み込みと明示的な読み込みの違いは何ですか?
  3. lazy loadingを使用し、たとえばdpc_gestion.dpc_participantを呼び出すと、ナビゲーションプロパティが読み込まれますか?または例外が発生しますか?
  4. パフォーマンスと応答性において、イージーロードまたは明示的なロードが遅延ロードよりも優れている場合はありますか?

ありがとう

24
Lamloumi Afif

この小さな履歴書が本当なら?

はい。

それが本当なら、熱心な読み込みと明示的な読み込みの違いは何ですか?

Eager loadingLazy loadingの反対ですが、明示的な読み込み遅延読み込みに似ていますが、を除いて:コードで関連データを明示的に取得します。ナビゲーションプロパティにアクセスしても、自動的には発生しません。エンティティのオブジェクト状態マネージャーエントリを取得し、コレクションのCollection.Loadメソッドまたは単一のエンティティを保持するプロパティのReference.Loadメソッドを呼び出すことにより、関連データを手動でロードします。

techblog から:

熱心なローディング:

Eager loadingはopposite ofLazy loadingです:特定の関連オブジェクトのセットを、クエリで明示的に要求されたオブジェクトとともにロードするプロセス。

明示的なロード:

明示的な読み込みは次のように定義されます。オブジェクトがクエリによって返されるとき、関連するオブジェクトは同時に読み込まれません。デフォルトでは、ナビゲーションプロパティのLoadメソッドを使用して明示的に要求されるまでロードされません。

そして:

遅延読み込みを使用して、たとえばdpc_gestion.dpc_participantを呼び出すと、ナビゲーションプロパティが読み込まれますか?それとも例外が発生しますか?

例外は発生せず、ナビゲーションプロパティが読み込まれます。

パフォーマンスと応答性において、イージーロードまたは明示的なロードが遅延ロードよりも優れている場合はありますか?

プライマリテーブルの取得されたすべての行に関連データが必要な場合、通常、積極的な読み込みの方が効率的です。また、リレーションが多すぎない場合、積極的な読み込みは、サーバー上のさらなるクエリを減らすための良い習慣です。しかし、プロパティをすぐに必要としないことがわかっている場合は、遅延ロードが適切な選択かもしれません。また、dbコンテキストが破棄され、遅延ロードが実行できなくなった状況では、積極的なロードが適切な選択です。たとえば、次のことを考慮してください。

public List<Auction> GetAuctions()
{
    using (DataContext db = new DataContext())
    {
        return db.Auctions.ToList();
    }
}

このメソッドを呼び出した後、dbが破棄され、Eager Loadingの方が適しているため、関連エンティティを遅延ロードすることはできませんここに。

もう1つ注意すべき点は、遅延読み込みはいくつかのSQL要求を生成し、一方で積極的な読み込み1つのリクエストでデータをロードします。 Eager loadingもORMでn + 1がissueを選択するのを解決するのに適した選択肢です。この投稿をご覧ください: n + 1選択の問題とは?

21
Salah Akbari

質問1および2:

遅延ローディングおよび熱負荷の説明は正しいです。
explicit loadingの使用は、説明したものとは少し異なります。

EntityFrameworkは、IQueryableオブジェクトを返します。これらのオブジェクトには、基本的にデータベースへのクエリが含まれています。ただし、これらは最初に列挙されるまで実行されません。
Loadはクエリを実行し、結果がローカルに保存されるようにします。
_Loadを呼び出すことは、ToListを呼び出してListを破棄することと同じですが、Listを作成するオーバーヘッドはありません。

質問3:

遅延読み込みを使用する場合、EntityFrameworknavigationプロパティの読み込みを処理するため、例外は発生しません。
これにはしばらく時間がかかり、アプリケーションが応答しなくなる可能性があることに注意してください

質問4:

切断された場合(ネットワークアプリケーションなど)では、を使用できません遅延読み込み。これらのオブジェクトはDTOに変換されてからEntityFrameworkによって追跡されません。

また、navigation propertyを使用することがわかっている場合は、ロードすることをお勧めしますeagerlyなので、ロードされるまで待つ必要はありませんデータベース。
たとえば、結果をリストに保存し、WPF DataGridにバインドするとします。 DataGridがまだロードされていないプロパティにアクセスする場合、ユーザーはそのプロパティが表示されるまで顕著なタイムアウトを経験します。さらに、アプリケーションはロード時に応答しません(非同期にロードしない場合)。

6
Domysee

ここでは、エンティティグラフに関連するエンティティを明示的に読み込む方法を学習します。 明示的な読み込みは、EF 6とEF Coreの両方で有効です。

(EF 6で)遅延読み込みを無効にしても、関連するエンティティを遅延読み込みすることは可能ですが、明示的な呼び出しで行う必要があります。 Load()メソッドを使用して、関連するエンティティを明示的にロードします。次の例を考えてみましょう。

_using (var context = new SchoolContext())
{
     var student = context.Students
                              .Where(s => s.FirstName == "Bill")
                             .FirstOrDefault<Student>();

     context.Entry(student).Reference(s => s.StudentAddress).Load(); 
     // loads StudentAddress
     context.Entry(student).Collection(s => s.StudentCourses).Load(); 
     // loads Courses collection      
}
_

上記の例では、context.Entry(student).Reference(s => s.StudentAddress).Load()StudentAddressエンティティをロードします。 Reference()メソッドは、指定された参照ナビゲーションプロパティのオブジェクトを取得するために使用され、Load()メソッドはそれを明示的にロードします。

同様に、context.Entry(student).Collection(s => s.Courses).Load()は、コレクションナビゲーションプロパティStudentエンティティのCoursesをロードします。 Collection()メソッドは、コレクションのナビゲーションプロパティを表すオブジェクトを取得します。

以下に示すように、Load()メソッドはデータベースでSQLクエリを実行して、データを取得し、メモリ内の指定された参照またはコレクションプロパティを満たします。 enter image description here
Query():LINQ-to-Entitiesクエリを記述して、ロードする前に関連データをフィルタリングすることもできます。 Query()メソッドを使用すると、関連エンティティのLINQクエリをさらに記述して、関連データを除外できます。

_using (var context = new SchoolContext())
{
    var student = context.Students
                    .Where(s => s.FirstName == "Bill")
                    .FirstOrDefault<Student>();

    context.Entry(student)
             .Collection(s => s.StudentCourses)
               .Query()
            .Where(sc => sc.CourseName == "Maths")
            .FirstOrDefault();
}     
_

上記の例では、.Collection(s => s.StudentCourses).Query()により、StudentCoursesエンティティに対するクエリをさらに記述できます。

1
Ghulam Dastgeer