EF LINQ comprend plusieurs entités imbriquées

155

Ok, j'ai des entités à trois niveaux avec la hiérarchie suivante: Cours -> Module -> Chapitre

Voici la déclaration EF LINQ originale:

Course course = db.Courses
                .Include(i => i.Modules.Select(s => s.Chapters))
                .Single(x => x.Id == id); 

Maintenant, je veux inclure une autre entité appelée Lab qui est associée à un cours.

Comment inclure l'entité Lab?

J'ai essayé ce qui suit mais cela n'a pas fonctionné:

Course course = db.Courses
                .Include(i => i.Modules.Select(s => s.Chapters) && i.Lab)
                .Single(x => x.Id == id); 

Des idées pour inclure la 2ème entité?

Tout conseil ou information serait très apprécié. Merci!

AnimaSola
la source
1
L'ajout d'un autre .Includedevrait fonctionner à moins que vous ne vouliez dire que l'inclusion supplémentaire est bien sûr un petit-enfant. Voir ceci ou une meilleure option est celle-ci
von v.2
Double

Réponses:

234

Avez-vous essayé d'ajouter un autre Include:

Course course = db.Courses
                .Include(i => i.Modules.Select(s => s.Chapters))
                .Include(i => i.Lab)
                .Single(x => x.Id == id);

Votre solution échoue car Includene prend pas d'opérateur booléen

Include(i => i.Modules.Select(s => s.Chapters) &&          i.Lab)
                           ^^^                  ^             ^ 
                          list           bool operator    other list

Mise à jour Pour en savoir plus, téléchargez LinqPad et parcourez les exemples. Je pense que c'est le moyen le plus rapide de se familiariser avec Linq et Lambda.

Pour commencer - la différence entre Selectet Includeest qu'avec un Select vous décidez ce que vous voulez retourner (aka projection). L'inclusion est une fonction de chargement hâtif, qui indique à Entity Framework que vous souhaitez qu'il inclue les données d'autres tables.

La syntaxe Inclure peut également être sous forme de chaîne. Comme ça:

           db.Courses
            .Include("Module.Chapter")
            .Include("Lab")
            .Single(x => x.Id == id);

Mais les exemples de LinqPad l' expliquent mieux.

Jens Kloster
la source
Appréciez-le! Où puis-je en savoir plus? Je suis particulièrement intéressé par la différence entre Include et Select
AnimaSola
3
Seulement celui - ci a fonctionné pour moi: .Include("Module.Chapter"). Une idée pourquoi cela serait-il?
Jo Smo
5
@JoSmo vous devez importer l'espace System.Data.Enityde noms pour accéder à la méthode d' extension. plus d'infos ici
Jens Kloster
using System.Data.Entity;l'a fait. Merci!
Jo Smo
1
voté pour avoir mentionné le brillant linqpad, et astuce pour utiliser System.Data.Entity, merci Jens
Mike
38

Dans Entity Framework Core ( EF.core), vous pouvez utiliser .ThenIncludepour inclure les niveaux suivants.

var blogs = context.Blogs
    .Include(blog => blog.Posts)
        .ThenInclude(post => post.Author)
    .ToList();

Plus d'informations: https://docs.microsoft.com/en-us/ef/core/querying/related-data

Note: Dites que vous avez besoin de plusieurs ThenInclude()sur blog.Posts, il suffit de répéter la Include(blog => blog.Posts)et faire une autre ThenInclude(post => post.Other).

var blogs = context.Blogs
    .Include(blog => blog.Posts)
        .ThenInclude(post => post.Author)
    .Include(blog => blog.Posts)
        .ThenInclude(post => post.Other)
 .ToList();
Nick N.
la source
Dans EF.core, il semble que je ne puisse pas faire .Include (i => i.Modules.Select (s => s.Chapters)), en particulier le .Select inside .Include. Quelqu'un peut-il confirmer ou parler?
ttugates
@ttugates Que comptez-vous faire avec cette sélection? Je pense que ce que vous voulez faire est exactement ce que vous faites ThenIncludedans EF core. Peut-être posez-vous une question avec un bon exemple, afin que nous puissions y répondre.
Nick N.18
@Nick N - Requête Linq Entity Framework: Comment accéder à plusieurs propriétés de navigation et sélectionner à partir de la 3e propriété de navigation . Parce que ce que je sélectionne n'est pas ce sur quoi je correspond, les inclusions ne sont pas nécessaires, donc la question est tangentielle. Ma question est peut-être trop "étroite" mais j'apprécie toute aide.
ttugates
1
Ah. En fait, .ThenInclude () fonctionne. Il faut juste une éternité à l'intellisense pour afficher les tables associées.
Chris J
23

Includefait partie de l'interface fluide, vous pouvez donc écrire plusieurs Includeinstructions les unes après les autres

 db.Courses.Include(i => i.Modules.Select(s => s.Chapters))
           .Include(i => i.Lab)
           .Single(x => x.Id == id); 
Ilya Ivanov
la source
appréciez-le! pouvez-vous m'indiquer où je peux en savoir plus? Merci!
AnimaSola
1
Savez-vous quelle est la syntaxe si les modules ont plusieurs tables que vous souhaitez joindre? Dites-lui des liens vers des chapitres et autre chose?
David Spence
Fluent fait-il partie de .Net ou s'agit-il d'une bibliothèque qui doit être installée?
codea
19

Vous pouvez également essayer

db.Courses.Include("Modules.Chapters").Single(c => c.Id == id);
Martin Larsson
la source
4
Merci - la notation par points dans la chaîne très utile
Evert
1
Cela peut être utile, mais une des raisons de ne pas l'utiliser est la facilité de refactorisation plus tard: si vous renommez l'entité "Chapitres" à un moment donné, l'autre exemple sera automatiquement renommé. Un autre est que les erreurs seront trouvées plus tôt: au moment de la compilation, pas au moment de l'exécution.
MGOwen le
2

On peut écrire une méthode d'extension comme celle-ci:

    /// <summary>
    /// Includes an array of navigation properties for the specified query 
    /// </summary>
    /// <typeparam name="T">The type of the entity</typeparam>
    /// <param name="query">The query to include navigation properties for that</param>
    /// <param name="navProperties">The array of navigation properties to include</param>
    /// <returns></returns>
    public static IQueryable<T> Include<T>(this IQueryable<T> query, params string[] navProperties)
        where T : class
    {
        foreach (var navProperty in navProperties)
            query = query.Include(navProperty);

        return query;
    }

Et utilisez-le comme ça même dans une implémentation générique:

string[] includedNavigationProperties = new string[] { "NavProp1.SubNavProp", "NavProp2" };

var query = context.Set<T>()
.Include(includedNavigationProperties);
Mohsen Afshin
la source
J'essayais votre réponse, mais cela jette des exceptions stackoverflow en raison d'une boucle infinie avec lui-même.
Victoria S.
1
@VictoriaS., Vous pouvez renommer la méthode d'extension afin qu'elle n'interfère pas avec le réelInclude
Mohsen Afshin