Ответ 1
Ваше описание (1) верное, но это пример загружаемой, а не ленивой загрузки.
Ваше описание (2) неверно. (2) технически не использует загрузку вообще, но будет использовать Lazy Loading, если вы попытаетесь получить доступ к любым нескалярным значениям на FlaggedDates.
В любом случае вы правы, что никакие данные не будут загружены из вашего хранилища данных, пока вы не попытаетесь "что-то сделать" с помощью _flaggedDates. Однако в каждом случае происходит то, что происходит.
(1): Желаемая загрузка: как только вы начнете цикл for
, каждый из объектов, которые вы указали, будет извлечен из базы данных и встроен в гигантскую структуру данных в памяти. Это будет очень дорогостоящая операция, вытащив огромное количество данных из вашей базы данных. Тем не менее, все это произойдет в одной базе данных в оба конца, при этом будет выполнен один запрос SQL.
(2): Lazy loading: Когда начнется цикл for
, он будет загружать только объекты FlaggedDates. Однако, если вы получаете доступ к связанным объектам внутри цикла for
, он не будет иметь эти объекты, загруженные в память. Первая попытка получить запланированные школы для данного объекта FlaggedDate приведет к тому, что новая база данных отправится в школу или выйдет исключение из-за того, что ваш контекст уже удален. Поскольку вы будете получать доступ к коллекции schedSchools внутри цикла for
, у вас будет новая обратная связь с базой данных для каждого объекта FlaggedDate, который вы первоначально загрузили в начале цикла for
.
Отклик на комментарии
Отключение Lazy Loading - это не то же самое, что включение Eager Loading. В этом примере:
context.ContextOptions.LazyLoadingEnabled = false;
var schools = context.FlaggedDates.First().scheduledSchools;
В переменной schools
будет пустое EntityCollection, потому что я не Include
их в исходном запросе (FlaggedDates.First()), и я отключил ленивую загрузку, чтобы они не могли быть загружены после начальный запрос был выполнен.
Вы правы, что where d.dateID == 2
будет означать, что будут втянуты только объекты, связанные с этим конкретным объектом FlaggedDate. Однако, в зависимости от того, сколько объектов связано с этим FlaggedDate, вы все равно можете получить много данные по этому проводу. Это связано с тем, как EntityFramework создает свой SQL-запрос. Результаты SQL Query всегда в табличном формате, то есть вы должны иметь одинаковое количество столбцов для каждой строки. Для каждого объекта schedSchool в результирующем наборе должна быть хотя бы одна строка, и поскольку каждая строка должна содержать по крайней мере некоторое значение для каждого столбца, вы получаете каждое скалярное значение в повторяющемся объекте FlaggedDate. Поэтому, если у вас есть 10 запланированных школ и 10 интервью, связанных с вашим FlaggedDate, у вас будет 20 строк, каждая из которых содержит каждое скалярное значение в FlaggedDate. Половина строк будет иметь нулевые значения для всех столбцов ScheduledSchool, а другая половина будет иметь нулевые значения для всех столбцов интервью.
Если это становится очень плохо, то, если вы идете "глубоко" в данные, которые вы включаете. Например, если каждая ScheduledSchool имела свойство students
, которое вы также включили, то вдруг у вас будет строка для каждого ученика в каждой ScheduledSchool, и в каждой из этих строк будет включено каждое скалярное значение для Student ScheduledSchool (хотя только первые значения строк в конечном итоге используются), а также каждое скалярное значение на исходном объекте FlaggedDate. Он может быстро складываться.
Трудно объяснить в письменной форме, но если вы посмотрите на фактические данные, возвращаемые из запроса с несколькими Include
s, вы увидите, что существует много дублированных данных. Вы можете использовать LinqPad для просмотра SQL-запросов, сгенерированных вашим EF-кодом.