web-dev-qa-db-fra.com

Chargement de toutes les entités enfants avec un cadre d'entité

J'ai un modèle de données comme celui-ci

Data Model

Je souhaite charger toutes les entités associées d'un rapprochement dans un objet de rapprochement. 

Pour l'instant, le seul moyen que j'ai pu trouver pour charger toutes les entités associées dans une seule reconnaissance est de créer plusieurs listes. Mais je veux charger toutes les entités liées dans un objet Reconciliation. Si possible de manière élégante.

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

J'ai aussi essayé de le charger avec Include et Select mais j'obtiens cette exception: 

L'expression de chemin d'accès inclus doit faire référence à une propriété de navigation définie sur le type. Utilisez des chemins en pointillé pour les propriétés de navigation de référence et l’opérateur Select pour les propriétés de navigation de collection. 

Et je ne comprends pas comment je pourrais charger tous les enfants de JrnlEntry en utilisant Include et Select

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))

Modifier

J'ai réussi à le faire aussi mais ce n'est pas très beau: 

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

Il existe deux manières d'effectuer Eager Loading dans Entity Framework:

Il y a aussi des façons d'écrire Requêtes SQL brutes contre base de données:

Dans ce cas, lorsque vous essayez de charger presque toute la base de données, il serait judicieux d’exécuter une procédure de stockage dédié.

26
Ryszard Dżegan

Essayez avec juste .Include(r => r.ReconciliationDetails) initialement. Ajoutez ensuite les instructions .Select() une par une. À quel moment l'exception se reproduit-elle? L'appel .SelectMany() me semble un peu méfiant!

Une deuxième question qui pourrait aider à identifier le problème ... Après avoir exécuté le code contenant tous les appels ToList(), votre entité recon est-elle complète? c'est-à-dire que toutes ses propriétés de navigation sont remplies? Ceci devrait être le cas en raison du comportement automatique de «correction» d'Entity Framework.

Avec EF, il est parfois plus efficace de charger un graphe d'objet complexe avec plusieurs appels plutôt que d'appels chaînés Include(). Vérifiez le code SQL généré et voyez ce qui est le plus efficace dans votre cas.

7
Olly

Pas sûr que ce soit trop tard, mais pourriez-vous tirer parti de la structuration de votre code tel que

var acctName = "someName";

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