web-dev-qa-db-fra.com

Comment fonctionne la syntaxe d'expression LINQ avec Include () pour un chargement rapide

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

1) Ma requête 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 pas rempli.

3) Essayez de charger ardemment "Utilisateur" dans la propriété de navigation en 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 essayant d'inclure, 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 ou une référence d'assembly à l'aide )

Je pense que c'est parce que LINQ ne prend pas en charge Include ().

J'ai donc essayé en VS; la requête 2 s'exécute, mais renvoie une propriété utilisateur non peuplée. Requête 3, la méthode d'extension ne semble pas exister, bien qu'elle existe sur Action elle-même sans la requête.

31
jaffa

Je l'ai compris, merci pour les suggestions de toute façon. La solution est de le faire (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 affiché Inclure après la requête était parce que j'avais besoin des éléments suivants en utilisant:

using System.Data.Entity;

Tout a bien fonctionné en faisant cela.

59
jaffa

Si vous voulez une requête qui retournera toutes les entités Action dont l'entité User associée existe réellement via le Action.UserIdpropriété de la clé étrangère , cela le fera:

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

Cependant vous n'avez pas besoin d'utiliser des propriétés de clé étrangère pour effectuer le filtrage , car vous avez également propriétés de navigation . Ainsi, votre requête peut être simplifiée en filtrant sur le Action.User propriété de navigation à 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 la propriété ne peut jamais être nulle (c.-à-d. la Action.UserId la clé étrangère n'est pas annulable dans la base de données) et ce que vous voulez est en fait toutes les entités Action avec leurs Users associées, la requête devient encore plus simple

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

Meilleur code convivial de refactorisation (EF6)

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

ou

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

Mise à jour du 31/03/2017

Vous pouvez également utiliser l'inclusion 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;
14
K0D4

En faisant la requête de base mentionnée dans votre question publiée, 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 ObjectContext, vous pouvez utiliser les éléments suivants:

Assurez-vous que LazyLoading est désactivé à l'aide de la ligne suivante:

entities.ContextOptions.LazyLoadingEnabled = false;

Procédez ensuite en

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

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 ça. ctx est votre DataContext. Cela fonctionne pour moi :-)

0
Mariusz