6

Könnte mir jemand helfen, den Unterschied zwischen zu klären:Include nicht ändert das Verhalten

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

ich die gleichen Ergebnisse in beiden Fällen erhalten, ohne den Unterschied zu kennen. Benötigt das Eager Loading Include?

+1

Welche Version von EF? In Versionen vor 7 funktionieren beide gleich. Der einzige Unterschied wäre die Rückgabe der 'People'-Sammlung ohne weitere Abfragen. Dann würde 'EmailAddresses' nur gefüllt werden, wenn sie aufgerufen werden (faul) –

+0

@RoyalBg: Ich benutze Version 6.1.3, Könnten Sie den Unterschied mehr erklären? –

+1

Angenommen, Sie müssen das Ergebnis der 'awlt.People'-Abfrage serialisieren. Ohne Include erhalten Sie keine E-Mail-Adressen. Aber wenn Sie sie vor der Serialisierung aufrufen (in diesem Fall 'Select'), erhalten Sie sie, so dass Sie sie nicht benötigen. In Version 7 brauchst du immer include (oder so war es vor einem Monat) –

Antwort

6

beide Abfrage Abrufen der entsprechenden Daten direkt mit dem ersten Abfrage von Eager Loading verwenden (und ja Eager Lade wird durch die Verwendung des Include Verfahrens erreicht, wie man vermutet) und die zweiten Abfrage unter Verwendung von Lazy loading die standardmäßig ist. Aber da Ihre Abfrage nur EmailAddresses wegen der Select() und SelectMany() Operationen zurückgibt, ändert die Include() Methode nicht das Verhalten. Um zu sehen, wennInclude() Methode Materie in Ihrem Beispiel ist lesen Sie die folgenden Zeilen, die ich es in einem Beispiel beweisen wird:

Um einen Unterschied zwischen diesen beiden Arten von Lade verbundenen Unternehmen Eager Laden wissen ist in der Regel effizienter, wenn Sie benötigen die zugehörigen Daten für alle abgerufenen Zeilen der Primärtabelle. Und auch wenn Relationen sindnicht zu viel, eifrig laden wird gute Praxis sein, um weitere Abfragen auf dem Server zu reduzieren. Aber wenn Sie wissen, dass Sie keine Immobilie sofort brauchen, dann ist das Lazy Loading vielleicht eine gute Wahl. Und auch das Eager Loading ist eine gute Wahl in Situationen, in denen der Db-Kontext entsorgt wird und das Lazy Loading nicht mehr möglich ist. Um zu beweisen, dass ein Lazy Loading-und eins ist Eager Laden Sie den folgenden Code betrachten:

public List<Person> GetEmailAddresses() 
{ 
    using (yourEntities awlt = new yourEntities()) 
    { 
     var query = awlt.People 
       .Where(p => p.LastName.Equals(lastName)); 
     return query.ToList(); 
    } 
} 

Nach dem Aufruf dieser Methode können Sie nicht die damit verbundene Einrichtung träge geladen werden, da die db angeordnet ist. Um zu beweisen, versuchen Sie dies:

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

Und Sie werden diesen Fehler erhalten:

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

Aber wenn Sie die GetEmailAddresses ändern Eager Laden verwenden wie folgt aus:

public List<Person> GetEmailAddresses() 
{ 
    using (yourEntities awlt = new yourEntities()) 
    { 
     var query = awlt.People.Include("EmailAddresses") 
       .Where(p => p.LastName.Equals(lastName)); 
     return query.ToList(); 
    } 
} 

Dann wird der Code unten sollte gut funktionieren:

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

Also in einer Situation, in der Ihr db-Kontext entsorgt würde, wäre die Eager Loading eine bessere Wahl.

+0

Übrigens ist der Fachbegriff für Lazy loading [Depered execution] das würde ich lieber verwenden. –

4

Ich weiß nichts über EF 7, aber in EF 6 erzeugen diese Anweisungen die gleichen Abfragen für die Datenbank und sind daher im Wesentlichen die gleichen. Es gibt kein faules Laden, kein eifriges Laden (in gewissem Sinne wird dieser Begriff üblicherweise benutzt).

Sie müssen Include nur Eigenschaften von Einheiten Sie materialisieren.Im obigen Beispiel materialisieren Sie Person.EmailAddresses.EmailAddress1, aber Sie enthalten nur Person.EmailAddresses - dies hat keine Auswirkungen (für weitere Details siehe zum Beispiel here).

Betrachten Sie diesen Beispielcode (Details keine Rolle spielt, da mit Codenavigationseigenschaft nur Fehler Entität):

// 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(); 

Und dieses:

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

Und mit umfassen:

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

Was ist eifrig laden? Dies ist der Fall, wenn Sie mit der Include-Anweisung zusätzliche Daten zur zugehörigen Entität hinzufügen. Hier Include-Anweisung hat keine Wirkung, es ist nur nichts, so dass wir nicht so eifrig laden nennen können.

Was ist Lazy Loading? Wenn die Navigationseigenschaft beim ersten Zugriff geladen wird. Sie tun dies nicht in Ihren Beispielen, also gibt es auch keine Lazy Loading.

Beide Beispiele führen nur identische Abfragen zur Datenbank aus (nachdem Sie sie mit der Enumeration `ToArray` etc.) realisiert haben.

+0

Ich habe zwei Entitäten 'People' &' EmailAddresses' 1-M –

+3

Ich verstehe, aber das ändert nichts - Include hat keinen Effekt in Ihrem Fall. Sie können dies selbst überprüfen, indem Sie beide Anweisungen ausführen und generiertes SQL für sie protokollieren. Ich habe einfach ein einfacheres Beispiel in meiner Antwort verwendet, um zu klären, wann Include _does_ Wirkung hat. – Evk

1

Das Ergebnis der beiden Abfragen ist genau das gleiche (auch über "eifrig" und "faul" laden).
In diesem Fall denke ich, dass auch die Abfrage sehr ähnlich sind oder die gleichen, aber nie EF Provider generierte Abfragen vertrauen. Um die generierten Abfragen zu sehen, können Sie das Programm mit einem Haltepunkt stoppen und nach dem Objekt suchen (mit der Maus darauf zeigen). Das ist die Abfrage, die von EF Provider generiert wird.

Über Eager laden (die Include-Anweisung) in diesem Fall sollte es nicht sinnvoll sein, weil zum Laden von Eigenschaften des Ausgabeobjekts verwendet wird. In diesem Fall wählen Sie EMailAddress1 aus, so dass Sie mit Include die Eigenschaften von EMailAddress1 laden können (und Lazy Queries während des EMailAddress1-Zugriffs vermeiden).

0

Sie können den Unterschied finden, wenn Sie in SQL Server Profiler nach der Abfrage suchen. Also im ersten Fall gibt es nur eine Abfrage an Ihre Datenbank und holen Datensätze aus People-Tabelle sowie EmailAddresses Tabelle, während im zweiten Fall es zwei Abfragen an die Datenbank und holt People zuerst und dann EmailAddresses in einer zweiten Abfrage. Daher wird das erste Szenario als "Eager Loading" und das zweite als "Lazy Loading" bezeichnet.

Verwandte Themen