Entity Framework-в чем разница между использованием Include / eager loading и ленивой загрузкой?

Я пытался ознакомиться с Entity Framework. Большинство из них кажется прямым, но я немного смущен разницей между нетерпеливой загрузкой с помощью метода Include и ленивой загрузкой по умолчанию. Кажется, что они загружают связанные объекты, поэтому на поверхности кажется, что они делают то же самое. Что я упускаю?

4 ответов


предположим, у вас есть два объекта с отношением "один ко многим": клиент и заказ, где каждый клиент может иметь несколько заказов.

при загрузке объекта клиента Entity Framework позволяет либо нетерпеливо загружать, либо лениво загружать коллекцию заказов клиента. Если вы хотите загрузить коллекцию заказов, при извлечении клиента из базы данных Entity Framework создаст SQL, который извлекает и информация о клиенте и Заказы клиента в одном запросе. Однако если вы решите лениво загружать коллекцию заказов, при извлечении клиента из базы данных Entity Framework будет генерировать SQL, который только извлекает информацию о клиенте (Entity Framework затем создаст отдельный оператор SQL, если вы получите доступ к коллекции заказов клиента позже в коде).

определение того, когда использовать нетерпеливую загрузку и когда использовать ленивую загрузку, сводится к тому, что вы ожидаете сделать с субъекты получения. Если вы знаете, что вам нужна только информация о клиенте, вы должны лениво загружать коллекцию заказов (чтобы SQL-запрос мог быть эффективным только путем получения информации о клиенте). И наоборот, если вы знаете, что вам нужно будет пройти через заказы клиента, то вы должны нетерпеливо загружать заказы (так что вы сохраните дополнительный удар по базе данных, как только получите доступ к заказам клиента в своем коде).

P. S. Будьте очень осторожны при использовании отложенной загрузки, так как это может приведите к проблеме N+1. Например, допустим, у вас есть страница, на которой отображается список клиентов и их заказов. Однако вы решили использовать lazy-loading при получении заказов. При итерации по коллекции Customers, а затем по заказам каждого клиента, вы будете выполнять хит базы данных для каждого клиента для ленивой загрузки в их коллекции заказов. Это означает, что для N клиентов у вас будет N + 1 попаданий в базу данных (1 попадание в базу данных для загрузки всех клиентов, затем N попаданий в базу данных для загрузки каждого из их заказов), а не только 1 хит базы данных, если бы вы использовали eager loading (который получил бы всех клиентов и их заказы в одном запросе).


Если вы пришли из мира SQL, подумайте о присоединении.

Если вы должны показать в сетке 10 заказов и клиент, который поставил заказ у вас есть 2 варианта:

1) ленивый нагрузки ( = 11 queryes = медленные спектакли)

EF будет снимать запрос для получения заказов и запрос для каждого заказа для получения данных клиента.

Select * from order where order=1
+
10 x (Select * from customer where id = (order.customerId))

1) нетерпеливая нагрузка (=1 запрос = высокая производительность)

эф снимет одиночное запрос для получения заказов и клиентов с помощью JOIN.

Select * from orders INNER JOIN customers on orders.customerId=customer.Id where order=1

PS: При извлечении объекта из БД объект сохраняется в кэше, пока контекст активен. В Примере, который я сделал с LAZY LOAD,если все 10 заказов относятся к одному и тому же клиенту вы увидите только 2 запроса, потому что, когда вы попросите EF получить объект, EF проверит, находится ли объект в кэше, и если он найдет, он не будет запускать другой SQL-запрос к ДЕЦИБЕЛ.


нетерпеливая загрузка предназначена для решения N+1 Выбирает проблема эндемична для ORMs. Краткая версия такова: если вы собираетесь напрямую получить некоторое количество сущностей, и вы знаете, что будете получать доступ к определенным связанным сущностям через извлеченные сущности, это много более эффективно извлекать все связанные объекты за один проход, по сравнению с их постепенным извлечением с помощью ленивой загрузки.


важной проблемой является сериализация. Корпорация Майкрософт рекомендует не использовать ленивую загрузку по умолчанию при работе с сериализованными объектами. Сериализация вызывает вызов всех связанных свойств, которые могут запустить цепную реакцию запрашиваемых связанных сущностей. Это действительно вступает в игру, если вы возвращаете данные JSON с контроллера. Данные JSON, очевидно, сериализованы. Вы либо хотите немедленно вернуть данные через Eager, либо отключить lazyloading в контексте и использовать Явная ленивая загрузка.