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!


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

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.


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();

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); 

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);

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);

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.