web-dev-qa-db-ja.com

エンティティフレームワークを使用してすべての子エンティティをロードする

私はこのようなデータモデルを持っています

Data Model

Reconciliationのすべての関連エンティティをReconciliationオブジェクトにロードします。

今のところ、関連するすべてのエンティティを単一のReconにロードできる唯一の方法は、複数のリストにあります。 ただし、関連するすべてのエンティティをReconciliationオブジェクトにロードしたい。可能であれば、エレガントな方法で。

Reconciliation recon = db.Reconciliations
  .Where(r => r.ReconNum == 382485).First();

List<ReconciliationDetail> reconDetails = recon.ReconciliationDetails.ToList();
List<JrnlEntryDetail> jrnlDetails = reconDetails.Select(r => r.JrnlEntryDetail).ToList();
List<JrnlEntry> jrnl = jrnlDetails.Select(j => j.JrnlEntry).ToList();

List<ARInvoice> invoices = jrnl.SelectMany(j => j.ARInvoices).ToList();
List<ARInvoiceDetail> invoicesDetail = invoices
  .SelectMany(i => i.ARInvoiceDetails).ToList();

List<ARCredMemo> credmemos = jrnl.SelectMany(j => j.ARCredMemoes).ToList();
List<ARCredMemoDetail> credmemosDetail = credmemos
  .SelectMany(c => c.ARCredMemoDetails).ToList();

List<IncomingPay> incomingPays = jrnl.SelectMany(j => j.IncomingPays).ToList();
List<IncomingPayDetail> incomingPaysDetail = incomingPays
  .SelectMany(i => i.IncomingPayDetails).ToList();

// ... and so on for outgoing pays, AP Invoices AP Cred Memo ...etc

IncludeSelectでロードしようとしましたが、この例外が発生します:

インクルードパス式は、タイプで定義されたナビゲーションプロパティを参照する必要があります。参照ナビゲーションプロパティには点線のパスを使用し、コレクションナビゲーションプロパティには選択演算子を使用します。

IncludeSelectを使用してJrnlEntryのすべての子をロードする方法がわかりません。

Reconciliation recon = db.Reconciliations
  .Where(r => r.ReconNum == 382485)
  .Include(r => r.ReconciliationDetails
    .Select(d => d.JrnlEntryDetail)
    .Select(jd => jd.JrnlEntry)
    .SelectMany(j => j.ARInvoices).SelectMany(i => i.ARInvoiceDetails))

編集

なんとかこの方法でもできましたが、あまり美しくありません:

Reconciliation recon = db.Reconciliations
.Where(r => r.ReconNum == 382485)
  .Include(r => r.ReconciliationDetails.Select(rd => rd.JrnlEntryDetail)
    .Select(jd => jd.JrnlEntry).Select(j => j.ARInvoices.Select(i => i.ARInvoiceDetails)))
  .Include(r => r.ReconciliationDetails.Select(rd => rd.JrnlEntryDetail)
    .Select(jd => jd.JrnlEntry).Select(j => j.ARCredMemoes.Select(c => c.ARCredMemoDetails)))
  .Include(r => r.ReconciliationDetails.Select(rd => rd.JrnlEntryDetail)
    .Select(jd => jd.JrnlEntry).Select(j => j.IncomingPays.Select(i => i.IncomingPayDetails)))
  .Include(r => r.ReconciliationDetails.Select(rd => rd.JrnlEntryDetail)
    .Select(jd => jd.JrnlEntry).Select(j => j.OutgoingPays.Select(o => o.OutgoingPayDetails)))
  .Include(r => r.ReconciliationDetails.Select(rd => rd.JrnlEntryDetail)
    .Select(jd => jd.JrnlEntry).Select(j => j.APInvoices.Select(o => o.APInvoiceDetails)))
  .Include(r => r.ReconciliationDetails.Select(rd => rd.JrnlEntryDetail)
    .Select(jd => jd.JrnlEntry).Select(j => j.APCredMemoes.Select(o => o.APCredMemoDetails)))
  .Include(r => r.ReconciliationDetails.Select(rd => rd.JrnlEntryDetail)
    .Select(jd => jd.JrnlEntry).Select(j => j.JrnlEntryDetails))
22
Arno 2501

Entity FrameworkでEager Loadingを実行するには2つの方法があります。

データベースに対して Raw SQLクエリ を記述する方法もあります。

この場合、データベースのほぼ全体をロードしようとする場合、専用のストアプロシージャを実行することをお勧めします。

26
Ryszard Dżegan

最初は.Include(r => r.ReconciliationDetails)だけで試してください。次に、.Select()ステートメントを1つずつ追加します。どの時点で例外が再発しますか? .SelectMany()呼び出しは少し疑わしいです!

問題の特定に役立つ2番目の質問...すべてのToList()呼び出しを含むコードを実行した後、reconエンティティは完全ですか?つまり、すべてのナビゲーションプロパティが設定されていますか?このshouldは、Entity Frameworkの自動「修正」動作のためです。

EFでは、チェーンされたInclude()呼び出しではなく、複数の呼び出しで複雑なオブジェクトグラフをロードする方が効率的な場合があります。生成されたSQLを確認し、あなたのケースで最も効率的なものを確認してください。

7
Olly

遅れるかどうかはわかりませんが、次のようなコードを構造化することでメリットが得られますか?

var acctName = "someName";

var detailList =  _repository.Include(e => e.JrnlEntryDetail).Filter(c => c.JrnlEntryDetail.Any(e => e.AcctName == acctName)).Get().ToList();
0
Jose Q