2011-10-03 21 views
10

Mi chiedo se esiste una possibilità di interessare entità correlate al carico per alcune sottoclassi di una determinata classe.Entity Framework - Eager caricamento di oggetti correlati sottoclasse

struttura di classe è inferiore

Ordine ha relazione con molte classi di base sottordine (SuborderBase). La classe MySubOrder eredita da SuborderBase. Voglio specificare il percorso di Include() per caricare entità correlate MySubOrder (Cliente) durante il caricamento dell'ordine, ma ho ricevuto un errore che afferma che non esiste alcuna relazione tra SuborderBase e Cliente. Ma esiste una relazione tra MySubOrder e il cliente.

Di seguito query che fallisce

Context.Orders.Include("SubOrderBases").Include("SubOrderBases.Customers") 

Come posso specificare che in modo esplicito?

Aggiornamento

. schema di entità è al di sotto enter image description here

+1

Probabilmente nessuna soluzione con caricamento avido. Ecco una soluzione alternativa con una proiezione (solo il terzo frammento di codice nella risposta accettata funziona, non il secondo frammento di codice, vedere i commenti alla risposta): http://stackoverflow.com/questions/6586574/bottleneck-using-entity-framework- eredità. Qui (http://stackoverflow.com/questions/7203303/how-do-i-deeply-eager-load-an-entity-with-a-reference-to-an-instance-of-a-persist) è stato un domanda simile senza risposta. – Slauma

+0

Potete abbozzare brevemente le classi e le relazioni nel codice ('Ordine',' OrdineDistretto', 'MySubOrder',' Cliente')? Guardando le risposte le persone sembrano fraintendere la tua domanda. Sto diventando incerto anche adesso, dopo le prime risposte e commenti. – Slauma

+0

Aggiunta immagine con diagramma di classe – Gopher

risposta

13

Si tratta di una soluzione che richiede solo un singolo andata e ritorno:

var orders = Context.Orders 
    .Select(o => new 
    { 
     Order = o, 
     SubOrderBases = o.SubOrderBases.Where(s => !(s is MyOrder)), 
     MyOrdersWithCustomers = o.SubOrderBases.OfType<MyOrder>() 
      .Select(m => new 
      { 
       MyOrder = m, 
       Customers = m.Customers 
      }) 
    }) 
    .ToList() // <- query is executed here, the rest happens in memory 
    .Select(a => 
    { 
     a.Order.SubOrderBases = new List<SubOrderBase>(
      a.SubOrderBases.Concat(
      a.MyOrdersWithCustomers.Select(m => 
       { 
        m.MyOrder.Customers = m.Customers; 
        return m.MyOrder; 
       }))); 
     return a.Order; 
    }) 
    .ToList(); 

fondamentalmente è una proiezione in un insieme di tipo anonimo. Successivamente il risultato della query viene trasformato in entità e proprietà di navigazione in memoria. (Funziona anche con il monitoraggio disattivato.)

Se non sono necessarie entità, è possibile omettere l'intera parte dopo il primo ToList() e lavorare direttamente con il risultato negli oggetti anonimi.

Se è necessario modificare questo grafico oggetto e hanno bisogno di rilevamento delle modifiche, non sono sicuro se questo approccio è sicuro perché le proprietà di navigazione non sono completamente impostati quando i dati vengono caricati - ad esempio MyOrder.Customers è null dopo la proiezione e quindi impostando le proprietà della relazione in memoria potrebbero essere rilevate come una modifica che non è e causano problemi quando si chiama SaveChanges.

Le proiezioni sono fatte per scenari di sola lettura, non per modifiche. Se è necessario modificare il rilevamento, probabilmente il modo più sicuro è caricare le entità complete in più roundtrip poiché non è possibile utilizzare Include in un singolo roundtrip per caricare l'intero grafico dell'oggetto nella situazione.

+0

Grazie! soluzione molto interessante!Non esattamente quello che volevo, ma penso che questo esempio sarà una grande fonte di ispirazione – Gopher

+9

Ottima risposta, ma che modo straordinariamente stupido di dover fare le cose. Chiunque penserebbe che il team EF abbia trascurato il fatto che i database relazionali hanno relazioni tra le tabelle. –

0

Supponiamo u caricato l'elenco ordini come lstOrders, provate questo:

foreach (Orders order in lstOrders) 
    order.SubOrderBases.Load(); 

e lo stesso per i clienti ..

+2

sì, ma sto pensando a come farlo con 1 query sql .. – Gopher

+2

prova questo: Context.Orders.Include ("SubOrderBases"). Include ("Customers") – Boomer

Problemi correlati