Я пытался познакомиться с Entity Framework. Большинство из них кажется прямым, но я немного смущен различием между нетерпением загрузки с помощью метода Include и стандартной ленивой загрузки по умолчанию. Кажется, что они загружают связанные объекты, поэтому на поверхности похоже, что они делают то же самое. Что мне не хватает?
Entity Framework - какая разница между использованием Include/нетерпеливой загрузки и ленивой загрузкой?
Ответ 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. Краткая версия такова: если вы собираетесь напрямую получить некоторое количество сущностей, и знаете, что вы будете получать доступ к определенным связанным объектам через извлеченные объекты, гораздо эффективнее получить все связанные сущности в один проход за один проход, по сравнению с их постепенным увеличением с помощью ленивой загрузки.