related query objects not multiple lazy framework entity-framework entity-framework-4 lazy-loading eager-loading

entity-framework - query - find entity framework



EF: carga perezosa, carga impaciente y "enumeraciĆ³n de los enumerables" (2)

Encuentro que estoy confundido acerca de la carga perezosa, etc.

Primero, son estas dos afirmaciones equivalentes:

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

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

Y en (2), la declaración cargará todas las entidades de navegación aunque no las solicites específicamente, porque estás usando una carga impaciente ... ¿verdad?

Segundo: incluso si está utilizando una carga impaciente, los datos no se descargarán realmente de la base de datos hasta que "enumere los enumerables", 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 realmente descargados ("enumerados") hasta que el bucle foreach ... ¿verdad? En otras palabras, la línea de "fechas de var" define la consulta, pero la consulta no se ejecuta hasta el bucle foreach.

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

(Mi experiencia específica es con el código primero, el desarrollo de POCO, por cierto ... aunque las preguntas pueden aplicarse de manera más general).


Ninguna diferencia. Esto no era cierto en EF 1.0, que no admite la carga impaciente (al menos no automáticamente). En 1.0, tuvo que modificar la propiedad para cargarla automáticamente o llamar al método Load () en la referencia de propiedad.

Una cosa que se debe tener en cuenta es que esos Incluye pueden desvanecerse si realiza consultas en varios objetos, como por ejemplo:

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

ObjectDate.MyObjectProperty no se cargará automáticamente.


Su descripción de (1) es correcta, pero es un ejemplo de Carga impaciente en lugar de Carga diferida.

Su descripción de (2) es incorrecta. (2) técnicamente no utiliza ninguna carga, pero utilizará la carga perezosa si intenta acceder a cualquier valor no escalar en sus fechas marcadas.

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

(1): Carga impaciente: tan pronto como comience su bucle for , cada uno de los objetos que haya 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, que extraerá una enorme cantidad de datos de su base de datos. Sin embargo, todo sucederá en un viaje de ida y vuelta de base de datos, con una sola consulta SQL ejecutándose.

(2): Carga diferida: cuando comience su bucle 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 Escuelas programadas para una FlaggedDate dada resultará en una nueva base de datos de ida y vuelta para recuperar las escuelas, o se lanzará una Excepción porque su contexto ya se ha eliminado. Ya que estaría accediendo a la colección scheduleSchools dentro de un bucle for , tendría una nueva base de datos de ida y vuelta para cada FlaggedDate que cargó inicialmente al principio del bucle for .

Respuesta a los comentarios

Deshabilitar la carga diferida no es lo mismo que habilitar la carga impaciente. En este ejemplo:

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

La variable schools contendrá una EntityCollection vacía, porque no los incluí en la consulta original (FlaggedDates.First ()), y deshabilité la carga perezosa para que no pudieran cargarse después de que se hubiera ejecutado la consulta inicial.

Usted tiene razón al decir que where d.dateID == 2 significaría que solo se obtendrían los objetos relacionados con ese objeto FlaggedDate específico. Sin embargo, dependiendo de cuántos objetos estén relacionados con esa FlaggedDate, todavía podría terminar con una gran cantidad de datos que pasan por ese cable. Esto se debe a la forma en que EntityFramework construye su consulta SQL. Los resultados de la consulta SQL siempre están en un formato tabular, lo que significa que debe tener el mismo número de columnas para cada fila. Para cada objeto programado en la escuela, debe haber al menos una fila en el conjunto de resultados, y como cada fila debe contener al menos algún valor para cada columna, terminará con cada valor escalar en su objeto FlaggedDate que se repite. Por lo tanto, si tiene 10 escuelas programadas 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, donde esto se pone realmente mal es si profundizas en los datos que estás incluyendo. Por ejemplo, si cada ScheduledSchool tuviera una propiedad de students , que también incluía, de repente tendría una fila para cada estudiante en cada ScheduledSchool, y en cada una de esas filas, se incluiría cada valor escalar para la ScheduledSchool del estudiante (incluso aunque solo se utilizan los valores de la primera fila, junto con cada valor escalar en el objeto FlaggedDate original. Se puede sumar rápidamente.

Es difícil de explicar por escrito, pero si observa los datos reales que provienen de una consulta con varios Include s, verá que hay muchos datos duplicados. Puede usar LinqPad para ver las consultas SQL generadas por su código EF.