19

Me parece que estoy confundido acerca de la carga diferida, etc.EF: La carga diferida, la carga ansiosa, y "la enumeración de la enumerables"

En primer lugar, estas son las dos declaraciones equivalentes:

(1) Lazy loading: 
_flaggedDates = context.FlaggedDates.Include("scheduledSchools") 
.Include ("interviews").Include("partialDayAvailableBlocks") 
.Include("visit").Include("events"); 

(2) Eager loading: 
_flaggedDates = context.FlaggedDates; 

En otra En palabras, en (1) el "Incluye" hace que las colecciones/propiedades de navegación se carguen junto con la colección específica solicitada, independientemente del hecho de que esté utilizando carga diferida ... ¿verdad?

Y en (2), la instrucción cargará todas las entidades de navegación aunque usted no las solicite específicamente, porque está utilizando la carga ansiosa ... ¿no?

Segundo: incluso si está utilizando la carga ansiosa, los datos no se realiza ningún descargado de la base de datos hasta que "enumera la numerable", como en el siguiente código:

var dates = from d in _flaggedDates 
      where d.dateID = 2 
      select d; 
foreach (FlaggedDate date in dates) 
{ 
... etc. 
} 

los datos no serán realidad ser descargado ("enumerado") hasta el ciclo foreach ... ¿verdad? En otras palabras, la línea "var dates" define la consulta, pero la consulta no se ejecuta hasta el ciclo foreach.

Teniendo en cuenta que (si mis suposiciones son correctas), ¿cuál es la diferencia real entre la carga ansiosa y la carga diferida? Parece que en cualquier caso, los datos no aparecen hasta la enumeración. ¿Me estoy perdiendo de algo?

(Mi experiencia específica es con un código-en primer lugar, el desarrollo POCO, por cierto ... a pesar de las preguntas pueden aplicarse de manera más general.)

+0

EntityFramework utiliza la carga impaciente/diferida (un término de software genérico para cómo se cargan los datos) para recuperar objetos y colecciones relacionados. La ejecución de consultas desviadas es un artefacto de LINQ que permite que las consultas sean más flexibles (es posible que no se ejecuten en absoluto en algunos escenarios). – jwize

Respuesta

17

Su descripción de (1) es correcta, pero es un ejemplo de Eager Loading en lugar de Lazy Loading.

Su descripción de (2) es incorrecta. (2) técnicamente no utiliza ninguna carga, pero utilizará la Carga diferida si intenta acceder a valores no escalares en sus fechas marcadas.

En cualquier caso, tiene razón en que no se cargarán datos de su almacén de datos hasta que intente "hacer algo" con _flaggedDates. Sin embargo, lo que sucede es diferente en cada caso.

(1): Carga ansiosa: tan pronto como comience su ciclo for, cada uno de los objetos que ha especificado se extraerá de la base de datos y se integrará en una gigantesca estructura de datos en memoria. Esta será una operación muy costosa, extrayendo una enorme cantidad de datos de su base de datos. Sin embargo, todo sucederá en una base de datos de ida y vuelta, con una única consulta SQL que se ejecutará.

(2): Carga diferida: Cuando comienza su ciclo for, solo cargará los objetos FlaggedDates. Sin embargo, si accede a objetos relacionados dentro de su bucle for, aún no tendrá esos objetos cargados en la memoria. El primer intento de recuperar las ScheduledSchools para un determinado FlaggedDate dará como resultado una nueva ida y vuelta a la base de datos para recuperar las escuelas, o una Excepción lanzada porque su contexto ya ha sido eliminado. Dado que accederá a la colección scheduledSchools dentro de un bucle for, tendrá una nueva base de datos ida y vuelta por cada fecha marcada que cargó inicialmente al comienzo del bucle for.

Reponse a los comentarios

Desactivación de Lazy Loading no es lo mismo que Habilitación Eager Cargando.En este ejemplo:

context.ContextOptions.LazyLoadingEnabled = false; 
var schools = context.FlaggedDates.First().scheduledSchools; 

La variable schools contendrán una EntityCollection vacío, porque no lo hice Include en la consulta original (FlaggedDates.First()), y la carga diferida I desactivada para que no pudiera ser cargado después de que la consulta inicial haya sido ejecutada.

Tiene razón en que el where d.dateID == 2 significa que solo se atraerán los objetos relacionados con ese objeto específico de FlaggedDate. Sin embargo, dependiendo de cuántos objetos estén relacionados con ese FlaggedDate, podría terminar con una gran cantidad de datos repasando ese cable. Esto se debe a la forma en que EntityFramework construye su consulta SQL. Los resultados de SQL Query están siempre en formato tabular, lo que significa que debe tener el mismo número de columnas para cada fila. Para cada objeto ScheduledSchool, debe haber al menos una fila en el conjunto de resultados, y dado que cada fila debe contener al menos algún valor para cada columna, se termina con cada valor escalar en su objeto FlaggedDate que se repite. Entonces, si tiene 10 SchoolsSchools y 10 entrevistas asociadas con su FlaggedDate, terminará con 20 filas que contienen cada valor escalar en FlaggedDate. La mitad de las filas tendrán valores nulos para todas las columnas de ScheduledSchool, y la otra mitad tendrá valores nulos para todas las columnas de Entrevistas.

Sin embargo, si esto llega a ser realmente malo, es si profundiza en los datos que está incluyendo. Por ejemplo, si cada escuela programada tenía una propiedad students, que también incluyó, de repente tendría una fila para cada estudiante en cada escuela programada, y en cada una de esas filas, se incluiría cada valor escalar para la escuela programada del alumno (incluso aunque solo los valores de la primera fila terminan usándose), junto con cada valor escalar en el objeto FlaggedDate original. Puede sumarse rápidamente.

Es difícil de explicar por escrito, pero si nos fijamos en los datos reales que provienen de una consulta con múltiples Include s, verá que hay una gran cantidad de datos duplicados. Puede usar LinqPad para ver las consultas SQL generadas por su código EF.

+0

Para (1) (MI (1), quise decir que se ha habilitado la Carga diferida. La afirmación es un ejemplo de carga ansiosa debido al Compártelo ... ¿no? – Cynthia

+0

Para (2) (MI (2)) ... Si La carga diferida está DESACTIVADA (en otras palabras, la carga está pendiente), ¿está diciendo que las propiedades de navegación no se cargarán junto con las fechas marcadas? Entonces, ¿qué significa cargar ansioso? – Cynthia

+0

Respuesta a sus ediciones: OK, veo lo que dice .Pero para su punto # 1: todos los objetos serán insertados, pero solo los especificados en su consulta, ¿verdad? Por ejemplo, en mi ejemplo dije donde d.dateID == 2, entonces solo los objetos para el objeto FlaggedDate with dateID = 2 tendría los datos ingresados. ¿No? Así que no sería tan caro siempre y cuando haya limitado el alcance de su consulta. – Cynthia

0

Sin diferencia. Esto no era cierto en EF 1.0, que no admitía la carga ansiosa (al menos no automáticamente). En 1.0, tenía que modificar la propiedad para cargarla automáticamente o llamar al método Load() en la referencia de la propiedad.

Una cosa a tener en cuenta es que los Incluye puede convertirse en humo si se consulta a través de múltiples objetos de esta manera:

from d in ctx.ObjectDates.Include("MyObjectProperty") 
from da in d.Days 

ObjectDate.MyObjectProperty no se cargará automáticamente.

Cuestiones relacionadas