Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

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

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

P.S. Будьте осторожны при использовании ленивой загрузки, так как это может привести к проблеме N + 1. Например, скажем, у вас есть страница, на которой отображается список клиентов и их заказы. Тем не менее, вы решили использовать ленивую загрузку при получении заказов. Когда вы перебираете коллекцию Клиентов, то над каждым Заказом Клиента вы будете выполнять попадание базы данных для каждого Клиента в ленивую загрузку в их коллекции Заказов. Это означает, что для клиентов N вы получите хиты базы данных N + 1 (1 база данных ударила, чтобы загрузить всех Клиентов, а затем N баз данных попадает для загрузки каждого из своих ордеров), а не только с одним ударом базы данных, если бы вы использовали активную загрузку (который мог бы получить всех Клиентов и их Заказы в одном запросе).

Ответ 2

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

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

1) LAZY LOAD (= 11 запросов = SLOW PERFORMANCES)

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

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

1) EAGER LOAD (= 1 query = HIGH PERFORMANCES)

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

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

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

Ответ 3

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