Qualcuno potrebbe aiutarmi a chiarire la differenza tra:
var query = awlt.People.Include(p => p.EmailAddresses)
.Where(p => p.LastName.Equals(lastName))
.SelectMany(a => a.EmailAddresses)
.Select(a => a.EmailAddress1);
var query = awlt.People
.Where(p => p.LastName.Equals(lastName))
.SelectMany(a => a.EmailAddresses)
.Select(a => a.EmailAddress1);
Ottengo gli stessi risultati in entrambi i casi senza sapere la differenza. Il caricamento avido richiede l'uso di Include
?
Entrambe le query recuperano i dati correlati solo la prima query utilizzando Eager Loading (e sì il caricamento Eager è ottenuto utilizzando il metodo Include
come indovinato) e la seconda query utilizzando il caricamento Lazy che è per impostazione predefinita. Ma dal momento che la query restituirà EmailAddresses
solo a causa delle operazioni Select()
e SelectMany()
, il metodo Include()
non modifica il comportamento . Per vedere quando il metodo Include()
è importante nel tuo esempio leggi le seguenti righe che lo dimostrerò in un esempio:
Per conoscere alcune differenze tra questo due tipi di entità correlate al caricamento, il caricamento Eager è in genere più efficiente quando sono necessari i dati correlati per tutte le righe recuperate della tabella primaria. E anche quando le relazioni non sono eccessive, il caricamento impaziente sarà una buona pratica per ridurre ulteriormente le query sul server. Ma quando sai che non avrai bisogno di una proprietà istantanea, allora il caricamento lento potrebbe essere una buona scelta. E anche il carico impaziente è una buona scelta in una situazione in cui il tuo contesto db viene eliminato e il caricamento lento non può più avvenire. Per dimostrare che uno è Lazy Loading e uno è Eager Loading considera il seguente codice:
public List<Person> GetEmailAddresses()
{
using (yourEntities awlt = new yourEntities())
{
var query = awlt.People
.Where(p => p.LastName.Equals(lastName));
return query.ToList();
}
}
Dopo aver chiamato questo metodo, non è possibile caricare l'entità correlata pigramente perché il db è eliminato. Per provare provare questo:
var query = GetEmailAddresses();
foreach (var item in query.SelectMany(a => a.EmailAddresses).Select(a => a.EmailAddress1))
{
MessageBox.Show(item);
}
E otterrai questo errore:
L'istanza ObjectContext è stata eliminata e non può più essere utilizzata per operazioni che richiedono una connessione.
Ma se cambi i GetEmailAddresses
per usare Eager Loading in questo modo:
public List<Person> GetEmailAddresses()
{
using (yourEntities awlt = new yourEntities())
{
var query = awlt.People.Include("EmailAddresses")
.Where(p => p.LastName.Equals(lastName));
return query.ToList();
}
}
Quindi il codice qui sotto dovrebbe funzionare bene:
var query = GetEmailAddresses();
foreach (var item in query.SelectMany(a => a.EmailAddresses).Select(a => a.EmailAddress1))
{
MessageBox.Show(item);
}
Quindi, in una situazione in cui il tuo contesto db sarebbe stato smaltito, il caricamento Eager sarebbe una scelta migliore.
Non so su EF 7, ma in EF 6 entrambe le istruzioni producono le stesse query sul database e quindi sono essenzialmente le stesse. Non vi è alcun caricamento pigro, nessun caricamento impaziente (in un certo senso questo termine viene solitamente utilizzato) di sorta.
Devi Include
solo le proprietà delle entità che ti sei materializzato . Nell'esempio sopra riportato materializzi Person.EmailAddresses.EmailAddress1
, ma includi solo Person.EmailAddresses
- questo non ha alcun effetto (per maggiori dettagli vedi per esempio qui ).
Considera questo codice di esempio (i dettagli non contano, c'è solo un'entità di errore con la proprietà di navigazione del codice):
// note we materialized query
var errors = ctx.Errors.Include(c => c.Code).ToArray();
// no lazy loading happens here - we already loaded all related Codes with Include
var codeIds = errors.Select(c => c.Code.CodeID).ToArray();
E questo:
// no need to include here!
var codeIds = ctx.Errors.Select(c =>c.Code.CodeID).ToArray();
E con include:
// include has no effect here!
var codeIds = ctx.Errors.Inlcude(c => c.Code).Select(c => c.Code.CodeID).ToArray();
Che cosa è il caricamento impaziente? È quando si includono dati aggiuntivi all'entità correlata utilizzando l'istruzione Include
. Qui la dichiarazione Includi non ha alcun effetto, non fa proprio nulla, quindi non possiamo nominare quel carico impaziente.
Cos'è il caricamento lazy? È quando la proprietà di navigazione viene caricata quando la accedi per la prima volta. Non lo fai nei tuoi esempi, quindi non c'è nemmeno il lazy loading.
Entrambi gli esempi eseguono query identiche nel database (dopo averle materializzate con enumeration`ToArray` ecc.).