Que fait Include () dans LINQ?

93

J'ai essayé de faire beaucoup de recherches, mais je suis plus un gars de la base de données - donc même l'explication dans le MSDN n'a aucun sens pour moi. Quelqu'un peut-il expliquer, et donner quelques exemples sur ce que fait la Include()déclaration dans le terme de la SQLrequête?

CJ
la source
Très basique, je ne connais que de simples Select, Where, Order by, quelques opérateurs d'agrégats. Je n'ai pas essayé JOIN dans LINQ, ni Include. Mon objectif ultime était de pouvoir réécrire ces requêtes LINQ en SQL
CJ

Réponses:

165

Disons par exemple que vous souhaitez obtenir une liste de tous vos clients:

var customers = context.Customers.ToList();

Et supposons que chaque Customerobjet a une référence à son ensemble de Orders, et que chacun Ordera des références LineItemsauxquelles peut également faire référence a Product.

Comme vous pouvez le voir, la sélection d'un objet de niveau supérieur avec de nombreuses entités associées peut entraîner une requête qui doit extraire des données de nombreuses sources. En tant que mesure des performances, Include()vous permet d'indiquer quelles entités associées doivent être lues à partir de la base de données dans le cadre de la même requête.

En utilisant le même exemple, cela peut amener tous les en-têtes de commande associés, mais aucun des autres enregistrements:

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

Enfin, depuis que vous avez demandé SQL, la première instruction sans Include()pourrait générer une instruction simple:

SELECT * FROM Customers;

La déclaration finale qui appelle Include("Orders")peut ressembler à ceci:

SELECT *
FROM Customers JOIN Orders ON Customers.Id = Orders.CustomerId;
Beurk
la source
1
Je vous remercie. En utilisant votre exemple, puis-je dire si je veux également inclure le LineItemset Products, la requête LINQ doit ressembler à ceci var customersWithOrderDetail = context.Customers.Include("Orders").Include("LineItems").Include("Products").ToList();:?
CJ
2
Oui, vous pouvez enchaîner plusieurs appels à Include()pour capturer des objets le long de "chemins" différents. Si vous voulez des objets dans le même chemin, vous n'avez qu'à faire un seul appel qui spécifie le chemin complet. Puisque LineItemset Productsne partagez aucun composant de chemin, vous avez besoin d'appels séparés.
Yuck
Est-il obligatoire d'utiliser Inclure? Je suis presque sûr d'avoir travaillé sur des solutions où je pourrais obtenir des objets liés sans les utiliser.
Jepzen
@Jepzen Cela dépend si vous utilisez ou non des entités chargées paresseusement.
Beurk le
@Yuck, je crois que cela fonctionne lorsque vous utilisez le chargement paresseux, en cas de chargement impatient, vous n'avez pas besoin d'utiliser l'instruction "include", mais cela entraînera certainement des problèmes de performances. Veuillez me corriger à ce sujet.
sam
27

Je voulais juste ajouter que "Inclure" fait partie d'un chargement impatient. Il est décrit dans le didacticiel Entity Framework 6 de Microsoft. Voici le lien: https://docs.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/reading-related-data-with-the -entité-cadre-dans-une-application-asp-net-mvc


Extrait de la page liée:

Voici plusieurs façons dont Entity Framework peut charger des données associées dans les propriétés de navigation d'une entité:

Chargement paresseux. Lors de la première lecture de l'entité, les données associées ne sont pas récupérées. Toutefois, la première fois que vous essayez d'accéder à une propriété de navigation, les données requises pour cette propriété de navigation sont automatiquement récupérées. Il en résulte plusieurs requêtes envoyées à la base de données - une pour l'entité elle-même et une à chaque fois que les données associées pour l'entité doivent être récupérées. La classe DbContext active le chargement différé par défaut.

Chargement avide. Lorsque l'entité est lue, les données associées sont récupérées avec elle. Cela se traduit généralement par une seule requête de jointure qui récupère toutes les données nécessaires. Vous spécifiez le chargement hâtif à l'aide de la Includeméthode.

Chargement explicite. Ceci est similaire au chargement différé, sauf que vous récupérez explicitement les données associées dans le code; cela ne se produit pas automatiquement lorsque vous accédez à une propriété de navigation. Vous chargez manuellement les données associées en obtenant l'entrée du gestionnaire d'état des objets pour une entité et en appelant la méthode Collection.Load pour les collections ou la méthode Reference.Load pour les propriétés qui contiennent une seule entité. (Dans l'exemple suivant, si vous souhaitez charger la propriété de navigation Administrateur, vous devez la remplacer Collection(x => x.Courses)par Reference(x => x.Administrator).) En règle générale, vous n'utilisez le chargement explicite que lorsque vous avez désactivé le chargement différé.

Comme ils ne récupèrent pas immédiatement les valeurs de propriété, le chargement différé et le chargement explicite sont également tous deux appelés chargement différé.

Minoosha
la source
3
Bienvenue dans SO =) Juste une suggestion, mais lorsque vous répondez à quelque chose comme ça, si vous le pouvez, incluez un extrait de code. Les liens peuvent malheureusement disparaître.
The_Cthulhu_Kid
2

Considérez-le comme l'application du chargement hâtif dans un scénario où vos sous-éléments seraient autrement un chargement paresseux.

L'EF de requête qui envoie à la base de données donnera un résultat plus important au début, mais lors de l'accès, aucune requête de suivi ne sera effectuée lors de l'accès aux éléments inclus.

D'un autre côté, sans cela, EF exécuterait des requêtes séparées plus tard, lorsque vous accédez pour la première fois aux sous-éléments.

robkrueger
la source