6

qualcuno potrebbe aiutarmi a chiarire la differenza tra:Utilizzando includono non cambia il comportamento

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 lo stesso risultato in entrambi i casi senza conoscere la differenza. Il caricamento desiderato richiede l'uso di Include?

+1

Quale versione di EF? Nelle versioni precedenti a 7, entrambe funzioneranno allo stesso modo. L'unica differenza sarebbe restituire la raccolta 'People' senza altre query. Quindi 'EmailAddresses' verrebbe compilato solo se invocato (pigro) –

+0

@RoyalBg: utilizzo la versione 6.1.3, potresti spiegare di più la differenza? –

+1

Diciamo che è necessario serializzare il risultato della query 'awlt.People'. Senza includere non riceverai gli indirizzi email. Ma se li invochi prima della serializzazione (in questo caso "Seleziona"), li riceverai, quindi non hai bisogno di includere. Nella versione 7 hai sempre bisogno di includere (o così è stato un mese fa) –

risposta

6

L'sia interrogazione stanno recuperando i dati relativi solo prima query utilizzando Eager Loading (e sì eager loading è ottenuta con l'uso del metodo di Include come avete indovinato) e la seconda query utilizzando Lazy loading che è per impostazione predefinita. Ma poiché la query restituirà solo EmailAddresses a causa delle operazioni Select() e SelectMany(), il metodo Include() non modifica il comportamento. Per vedere quandoInclude() metodo è la materia nel tuo esempio leggere le seguenti righe che io lo dimostrerò in un esempio:

conoscere alcune differenze tra questi due tipi di entità correlate di carico eager loading è in genere più efficiente quando hai bisogno dei dati relativi per tutte le righe recuperate della tabella primaria. E anche quando i rapporti sononon troppo, carico eccessivo sarà una buona pratica per ridurre ulteriori 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 è pigro Caricamento e uno è desideroso Caricamento considerare 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 è disposto. Per dimostrare provare questo:

var query = GetEmailAddresses(); 
foreach (var item in query.SelectMany(a => a.EmailAddresses).Select(a => a.EmailAddress1)) 
{ 
    MessageBox.Show(item);     
} 

Ed otterrete questo errore:

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

Ma se si cambia la GetEmailAddresses di utilizzare 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(); 
    } 
} 

Poi 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 contesto db sarebbe stato smaltito, il Eager Loading sarebbe una scelta migliore.

+0

A proposito, il termine tecnico per il caricamento Lazy è [Esecuzione corretta] Preferisco usarlo. –

4

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.

È necessario Include solo le proprietà delle entità che si materialize.Nell'esempio sopra riportato si materializza Person.EmailAddresses.EmailAddress1, ma si include solo Person.EmailAddresses - questo non ha alcun effetto (per maggiori dettagli si veda ad esempio here).

Considerate questo codice di esempio (i dettagli non importa, c'è solo un'entità errore con codice di proprietà di navigazione):

// 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 includono:

// include has no effect here! 
var codeIds = ctx.Errors.Inlcude(c => c.Code).Select(c => c.Code.CodeID).ToArray(); 

Che cosa è il caricamento bisognoso? È quando si includono dati aggiuntivi all'entità correlata utilizzando l'istruzione Include. Qui la dichiarazione Incluse ha l'effetto no, non fa nulla, quindi non possiamo nominare quel carico impaziente.

Che 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 averli materializzati con enumeration`ToArray` ecc.).

+0

Ho due entità 'People' e' EmailAddresses' 1-M –

+3

Capisco ma questo non modifica nulla - Includi non ha alcun effetto nel tuo caso. Puoi verificarlo da solo eseguendo entrambe le istruzioni e l'SQL generato dalla registrazione per loro. Ho appena usato un esempio più semplice nella mia risposta per chiarire quando Include _does_ ha effetto. – Evk

1

Il risultato delle due query è esattamente lo stesso (anche per il carico "impaziente" e "pigro").
In questo caso penso che anche la query sia molto simile o la stessa MA non si fidi mai delle query generate dal provider EF. Per vedere le query generate puoi fermare il programma con un breakpoint e dare un'occhiata all'oggetto query (puntando il mouse su di esso). Questa è la query generata dal provider EF.

Informazioni sul caricamento di Eager (l'istruzione Includi) in questo caso non dovrebbe essere utile perché viene utilizzato per caricare le proprietà dell'oggetto di output. In questo caso, si seleziona EMailAddress1 quindi con Includi è possibile caricare le proprietà di EMailAddress1 (ed evitare le query lazy durante l'accesso a EMailAddress1).

0

È possibile trovare la differenza se si analizza SQL Server Profiler dopo l'esecuzione della query. Quindi nel tuo primo caso c'è una sola query che va al tuo database e recupera i record dalla tabella People così come la tabella EmailAddresses mentre nel secondo caso fa due query al database e recupera People in primo luogo e poi EmailAddress in una seconda query. Quindi il primo scenario è chiamato caricamento impaziente e il secondo caricamento lento.

Problemi correlati