42 votes

Comment la syntaxe d'expression LINQ fonctionne-t-elle avec Include() pour le chargement rapide ?

J'ai une requête ci-dessous, mais je veux effectuer un Include() pour charger avidement les propriétés. Actions a une propriété de navigation, User (Action.User)

1) Ma question de base :

from a in Actions
join u in Users on a.UserId equals u.UserId
select a

2) Première tentative :

from a in Actions.Include("User")
join u in Users on a.UserId equals u.UserId
select a

Mais Action.User est no populeux.

3) Essayez de charger "User" dans la propriété de navigation de l'action en dehors de la requête :

(from a in Actions
join u in Users on a.UserId equals u.UserId    
select a).Include("User")

Dans LINQPad en essayant les Include's j'obtiens une erreur :

System.Linq.IQueryable' ne contient pas de définition pour 'Include' et aucune méthode d'extension 'Include' acceptant un premier argument de type 'System.Linq.IQueryable' n'a pu être trouvée (appuyez sur F4 pour ajouter une directive using ou une référence d'assemblage).

Je pense que c'est parce que LINQ ne supporte pas Include().

J'ai donc essayé dans VS ; la requête 2 fonctionne, mais renvoie une propriété utilisateur non remplie. Pour la requête 3, la méthode d'extension ne semble pas exister, bien qu'elle existe sur l'action elle-même sans la requête.

69voto

jaffa Points 6567

J'ai compris, merci quand même pour les suggestions. La solution consiste à faire ceci (2ème tentative dans ma question) :

var qry = (from a in Actions
join u in Users on a.UserId equals u.UserId    
select a).Include("User")

La raison pour laquelle intellisense n'a pas montré Include après la requête est que j'avais besoin de l'utilisation suivante :

using System.Data.Entity;

Tout a bien fonctionné en faisant ça.

21voto

Barrakoda Points 175

Un code plus performant et facile à refacturer (EF6)

using System.Data.Entity;
[...]
var x = (from cart in context.ShoppingCarts
         where table.id == 123
         select cart).Include(t => t.CartItems);

o

var x = from cart in context.ShoppingCarts.Include(nameof(ShoppingCart.CartItems))
        where table.id == 123
        select cart;

Mise à jour 3/31/2017

Vous pouvez également utiliser include dans la syntaxe lambda pour l'une ou l'autre méthode :

var x = from cart in context.ShoppingCarts.Include(p => p.ShoppingCart.CartItems))
        where table.id == 123
        select cart;

17voto

Enrico Campidoglio Points 17157

Si ce que vous voulez est une requête qui renvoie tous les Action les entités dont les User existe réellement via le Action.UserId propriété de la clé étrangère ceci fera l'affaire :

var results = context.Actions
    .Include("User")
    .Where(action =>
        context.Users.Any(user =>
            user.UserId == action.UserId));

Cependant il n'est pas nécessaire d'utiliser les propriétés des clés étrangères pour effectuer le filtrage. puisque vous avez aussi propriétés de navigation . Ainsi, votre requête peut être simplifiée en filtrant sur l'élément Action.User à la place, comme dans cet exemple :

var results = context.Actions
    .Include("User")
    .Where(action => action.User != null);

Si votre modèle indique que le Action.User ne peut jamais être nulle (c'est-à-dire que la propriété Action.UserId clé étrangère n'est pas annulable dans la base de données) et ce que vous voulez est en fait tout ce que vous pouvez faire. Action avec les entités qui leur sont associées Users alors la requête devient encore plus simple

var results = context.Actions.Include("User");

2voto

Ryan Points 108

En effectuant la requête de base mentionnée dans votre question, vous ne pourrez pas voir les propriétés de l'utilisateur à moins que vous ne retourniez un type anonyme comme suit :

from a in Actions
join u in Users on a.UserId equals u.UserId
select new
{
   actionUserId = a.UserId
   .
   .
   .
   userProperty1 = u.UserId
};

Cependant, pour utiliser la méthode Include sur l'ObjectContext, vous pouvez utiliser ce qui suit :

Assurez-vous que LazyLoading est désactivé en utilisant la ligne suivante :

entities.ContextOptions.LazyLoadingEnabled = false;

Ensuite, procédez comme suit

var bar = entities.Actions.Include("User");
var foo = (from a in bar
           select a);

0voto

Mariusz Points 1115

J'utilise pour cela l'option LoadWith

var dataOptions = new System.Data.Linq.DataLoadOptions();
dataOptions.LoadWith<Action>(ac => as.User);
ctx.LoadOptions = dataOptions;

C'est tout. ctx est votre DataContext. Cela fonctionne pour moi :-)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X