EF LINQ incluye entidades múltiples y anidadas

155

Ok, tengo entidades de tres niveles con la siguiente jerarquía: Curso -> Módulo -> Capítulo

Aquí estaba la declaración original de EF LINQ:

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

Ahora, quiero incluir otra entidad llamada Lab que está asociada con un curso.

¿Cómo incluyo la entidad Lab?

Intenté lo siguiente pero no funcionó:

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

¿Alguna idea sobre la inclusión de la 2da entidad?

Cualquier consejo o información sería muy apreciada. ¡Gracias!

AnimaSola
fuente
1
Agregar otro .Includedebería funcionar a menos que quiera decir que la inclusión adicional es un nieto de Course. Vea esto o una mejor opción es esta
von v.
Duplicado relacionado / posible de stackoverflow.com/q/3356541
StuartLC

Respuestas:

234

¿Has probado simplemente agregando otro Include?

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

Su solución falla porque Includeno toma un operador booleano

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

Actualización Para obtener más información, descargue LinqPad y consulte los ejemplos. Creo que es la forma más rápida de familiarizarse con Linq y Lambda.

Para empezar, la diferencia entre Selecty Includees que con un Select usted decide lo que quiere devolver (también conocido como proyección). La función Incluir es Eager Loading , que le dice a Entity Framework que desea que incluya datos de otras tablas.

La sintaxis de Incluir también puede estar en cadena. Me gusta esto:

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

Pero las muestras en LinqPad explican esto mejor.

Jens Kloster
fuente
¡Lo aprecio! ¿Dónde puedo aprender más de esto? Estoy especialmente interesado en la diferencia entre Incluir y Seleccionar
AnimaSola
3
Sólo que ésta funcionó para mí: .Include("Module.Chapter"). ¿Alguna idea de por qué sería eso?
Jo Smo
55
@JoSmo necesita importar el espacio System.Data.Enityde nombres para acceder al método de extensión. más información aquí
Jens Kloster
using System.Data.Entity;lo hizo. ¡Gracias!
Jo Smo
1
votó por mencionar el brillante linqpad y la sugerencia de usar System.Data.Entity, gracias Jens
Mike
38

En Entity Framework Core ( EF.core) puede usar .ThenIncludepara incluir los siguientes niveles.

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

Más información: https://docs.microsoft.com/en-us/ef/core/querying/related-data

Nota: Digamos que usted necesita múltiples ThenInclude()en blog.Posts, sólo tiene que repetir el Include(blog => blog.Posts)y hacer otraThenInclude(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.
fuente
En EF.core parece que no puedo hacer .Include (i => i.Modules.Select (s => s.Chapters)), específicamente el .Select dentro de .Include. ¿Alguien puede confirmar o hablar?
ttugates
@ttugates ¿Qué piensas hacer con esta selección? Creo que lo que quieres hacer es exactamente lo que haces con ThenIncludeEF core. Tal vez haga una pregunta con un buen ejemplo, para que podamos responderla.
Nick N.
@Nick N - Entity Framework Linq Query: Cómo llegar a varias propiedades de navegación y seleccionar desde la tercera propiedad de navegación . Debido a que lo que selecciono no es con lo que coincido, las inclusiones no son necesarias, por lo que la pregunta es tangencial. Mi pregunta puede ser demasiado "estrecha", pero agradezco cualquier ayuda.
ttugates
1
Ah En realidad, .ThenInclude () funciona. Solo lleva una eternidad que el intellisense muestre las tablas relacionadas.
Chris J
23

Includeforma parte de una interfaz fluida, por lo que puede escribir varias Includedeclaraciones una tras otra

 db.Courses.Include(i => i.Modules.Select(s => s.Chapters))
           .Include(i => i.Lab)
           .Single(x => x.Id == id); 
Ilya Ivanov
fuente
¡lo aprecio! ¿podría indicarme dónde puedo aprender más sobre esto? ¡Gracias!
AnimaSola
1
¿Sabes cuál es la sintaxis si los módulos tienen varias tablas que quieres unir? ¿Decir que enlaza con capítulos y algo más?
David Spence
¿Fluye parte de .Net o es una biblioteca que necesita ser instalada?
codea
19

También puedes probar

db.Courses.Include("Modules.Chapters").Single(c => c.Id == id);
Martin Larsson
fuente
44
Gracias. La notación de puntos en la cadena es muy útil
Evert
1
Esto puede ser útil, pero una razón para no usar esto es la facilidad de refactorización posterior: si cambia el nombre de la entidad "Capítulos" en algún momento, el otro ejemplo cambiará de nombre automáticamente. Otra es que los errores se encontrarán antes: en tiempo de compilación, no en tiempo de ejecución.
MGOwen
2

Uno puede escribir un método de extensión como este:

    /// <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;
    }

Y úsalo así incluso en una implementación genérica:

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

var query = context.Set<T>()
.Include(includedNavigationProperties);
Mohsen Afshin
fuente
Estaba probando su respuesta, pero arroja excepciones de desbordamiento de pila debido a un bucle infinito consigo mismo.
Victoria S.
1
@VictoriaS., Puede cambiar el nombre del método de extensión para que no interfiera con lo realInclude
Mohsen Afshin