Что делает Include () в LINQ?

96

Я попытался провести много исследований, но я больше люблю db - поэтому даже объяснение в MSDN не имеет для меня никакого смысла. Может ли кто-нибудь объяснить и предоставить несколько примеров того, что Include()утверждение делает в термине SQLзапроса?

CJ
источник
Очень простой, я знаю только простые Select, Where, Order by, некоторые совокупные операторы. Я не пробовал JOIN в LINQ или Include. Моей конечной целью было переписать эти LINQ-запросы в SQL
CJ

Ответы:

169

Допустим, вы хотите получить список всех своих клиентов:

var customers = context.Customers.ToList();

И давайте предположим, что каждый Customerобъект имеет ссылку на свой набор Orders, и что у каждого Orderесть ссылки, LineItemsкоторые также могут ссылаться на файл Product.

Как видите, выбор объекта верхнего уровня со многими связанными сущностями может привести к запросу, который должен получать данные из многих источников. В качестве показателя производительности Include()позволяет указать, какие связанные сущности должны быть прочитаны из базы данных в рамках одного запроса.

Используя тот же пример, это может привести к появлению всех связанных заголовков заказов, но ни одной из других записей:

var customersWithOrderDetail = context.Customers.Include("Orders").ToList();

В качестве последнего момента, поскольку вы запросили SQL, первый оператор без него Include()может сгенерировать простой оператор:

SELECT * FROM Customers;

Последний оператор, который вызывает вызовы, Include("Orders")может выглядеть так:

SELECT *
FROM Customers JOIN Orders ON Customers.Id = Orders.CustomerId;
Фу
источник
1
Спасибо. Используя ваш пример, могу ли я сказать, хочу ли я также включить LineItemsи Products, запрос LINQ должен выглядеть так var customersWithOrderDetail = context.Customers.Include("Orders").Include("LineItems").Include("Products").ToList();:?
CJ
2
Да, вы можете объединить несколько вызовов в цепочку для Include()захвата объектов по разным «путям». Если вы хотите, чтобы объекты располагались по одному и тому же пути, вам нужно сделать только один вызов, который указывает весь путь. Поскольку компоненты пути LineItemsи Productsне разделяют, вам нужны отдельные вызовы.
Yuck
Обязательно ли использовать Include? Я почти уверен, что работал над решениями, позволяющими получать связанные объекты без его использования.
Jepzen
@Jepzen Это зависит от того, используете ли вы ленивые объекты или нет.
Yuck
@Yuck, я считаю, что это работает, когда вы используете ленивую загрузку, в случае активной загрузки вам не нужно использовать оператор include, но это определенно приведет к проблемам с производительностью. Пожалуйста, поправьте меня по этому поводу.
Сэм
27

Я просто хотел добавить, что «Включить» - это часть активной загрузки. Он описан в руководстве по Entity Framework 6 от Microsoft. Вот ссылка: https://docs.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/reading-related-data-with-the -entity-framework-в-asp-net-MVC-приложении


Выдержка со связанной страницы:

Вот несколько способов, которыми Entity Framework может загружать связанные данные в свойства навигации объекта:

Ленивая загрузка. При первом чтении объекта связанные данные не извлекаются. Однако при первой попытке доступа к свойству навигации данные, необходимые для этого свойства навигации, извлекаются автоматически. Это приводит к тому, что в базу данных отправляется несколько запросов - один для самой сущности и один каждый раз, когда необходимо получить связанные данные для этой сущности. Класс DbContext по умолчанию включает отложенную загрузку.

Нетерпеливая загрузка. Когда объект читается, вместе с ним извлекаются связанные данные. Обычно это приводит к единственному запросу соединения, который извлекает все необходимые данные. Вы указываете активную загрузку с помощью Includeметода.

Явная загрузка. Это похоже на отложенную загрузку, за исключением того, что вы явно извлекаете связанные данные в коде; это не происходит автоматически при доступе к свойству навигации. Вы загружаете связанные данные вручную, получая запись диспетчера состояний объекта для сущности и вызывая метод Collection.Load для коллекций или метод Reference.Load для свойств, содержащих одну сущность. (В следующем примере, если вы хотите загрузить свойство навигации администратора, вы должны заменить его Collection(x => x.Courses)на Reference(x => x.Administrator).) Обычно вы используете явную загрузку только тогда, когда вы отключили отложенную загрузку.

Поскольку они не сразу получают значения свойств, отложенная загрузка и явная загрузка также известны как отложенная загрузка.

Minoosha
источник
3
Добро пожаловать в SO =) Просто предложение, но когда вы отвечаете на что-то подобное, если можете, включите фрагмент кода. К сожалению, ссылки могут пропасть.
The_Cthulhu_Kid
2

Думайте об этом как о принудительной загрузке в сценарии, в котором ваши подпункты иначе загружались бы лениво.

EF запроса, отправляемый в базу данных, сначала даст больший результат, но при доступе никакие последующие запросы не будут выполняться при доступе к включенным элементам.

С другой стороны, без него EF будет выполнять отдельные запросы позже, когда вы впервые обращаетесь к подпунктам.

Робкрюгер
источник