O EF LINQ inclui entidades múltiplas e aninhadas

155

Ok, eu tenho entidades de três níveis com a seguinte hierarquia: Curso -> Módulo -> Capítulo

Aqui estava a declaração EF LINQ original:

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

Agora, quero incluir outra entidade chamada Lab, associada a um curso.

Como faço para incluir a entidade do laboratório?

Eu tentei o seguinte, mas não funcionou:

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

Alguma idéia de como incluir a 2ª entidade?

Qualquer conselho ou informação seria muito apreciada. Obrigado!

AnimaSola
fonte
1
Adicionar outro .Includedeve funcionar, a menos que você queira dizer que a inclusão adicional é um neto do curso. Veja isto ou uma opção melhor é esta
von v.
Relacionado / possível duplicado de stackoverflow.com/q/3356541
StuartLC 6/18

Respostas:

234

Você já tentou adicionar outro Include:

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

Sua solução falha porque Includenão leva um operador booleano

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

Atualização Para saber mais, faça o download do LinqPad e veja as amostras. Eu acho que é a maneira mais rápida de se familiarizar com Linq e Lambda.

Para começar - a diferença entre Selecte Includeé que, com um Select, você decide o que deseja retornar (também conhecido como projeção). A função Incluir é uma carga ansiosa , que informa ao Entity Framework que você deseja que ele inclua dados de outras tabelas.

A sintaxe Incluir também pode estar na sequência. Como isso:

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

Mas as amostras no LinqPad explicam isso melhor.

Jens Kloster
fonte
Aprecie! Onde posso aprender mais sobre isso? Estou especialmente interessado na diferença entre Incluir e selecione
AnimaSola
3
Só que este trabalhou para mim: .Include("Module.Chapter"). Alguma idéia de por que isso seria?
Jo Smo
5
@JoSmo, você precisa importar o espaço System.Data.Enitypara nome para acessar o método de extensão. mais informações aqui
Jens Kloster
using System.Data.Entity;fez isso. Obrigado!
Jo Smo
1
upvoted para mencionar o LINQPad brilhante, e dica para usar System.Data.Entity, thx Jens
Mike
38

No Entity Framework Core ( EF.core), você pode usar .ThenIncludepara incluir os próximos níveis.

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

Mais informações: https://docs.microsoft.com/en-us/ef/core/querying/related-data

Nota: Diga que você precisa múltipla ThenInclude()on blog.Posts, basta repetir o Include(blog => blog.Posts)e fazem outra 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.
fonte
No EF.core, parece que não consigo fazer .Include (i => i.Modules.Select (s => s.Chapters)), especificamente o .Select dentro de .Include. Alguém pode confirmar ou falar?
ttugates
@ttugates O que você pretende fazer com essa seleção? Eu acho que o que você quer fazer é exatamente o que você faz ThenIncludeno núcleo da EF. Talvez faça uma pergunta com um bom exemplo, para que possamos respondê-la.
Nick N.
@Nick N - Consulta Linq do Entity Framework: Como acessar várias propriedades de navegação e selecionar na 3ª propriedade de navegação . Como o que eu seleciono não é o que eu estou correspondendo, as inclusões não são necessárias, portanto a pergunta é tangencial. Minha pergunta pode ser muito "estreita", mas agradeço qualquer ajuda.
ttugates
1
Ah Na verdade, .ThenInclude () funciona. Leva apenas uma eternidade para o intellisense exibir as tabelas relacionadas.
Chris J
23

Includefaz parte da interface fluente, para que você possa escrever várias Includeinstruções uma após a outra

 db.Courses.Include(i => i.Modules.Select(s => s.Chapters))
           .Include(i => i.Lab)
           .Single(x => x.Id == id); 
Ilya Ivanov
fonte
aprecio isso! você poderia me indicar onde eu posso aprender mais sobre isso? Obrigado!
AnimaSola
1
Você sabe qual é a sintaxe se o Modules tiver várias tabelas nas quais você deseja ingressar? Diga que tem links para capítulos e mais alguma coisa?
David Spence
É parte fluente do .Net ou é uma biblioteca que precisa ser instalada?
codea
19

Você também pode tentar

db.Courses.Include("Modules.Chapters").Single(c => c.Id == id);
Martin Larsson
fonte
4
Obrigado - a notação de ponto na string é muito útil #
Evert
1
Isso pode ser útil, mas um motivo para não usar isso é a facilidade de refatoração posterior: se você renomear a entidade "Capítulos" em algum momento, o outro exemplo será renomeado automaticamente. Outra é que os erros serão encontrados mais cedo: no tempo de compilação, não no tempo de execução.
MGOwen 14/04
2

Pode-se escrever um método de extensão 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;
    }

E use-o assim mesmo em uma implementação genérica:

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

var query = context.Set<T>()
.Include(includedNavigationProperties);
Mohsen Afshin
fonte
Eu estava tentando sua resposta, mas está lançando exceções de fluxo de pilha devido a um loop infinito consigo mesmo.
Victoria S.
1
. @VictoriaS, você pode renomear o método de extensão para que ele não interfira com o realInclude
Mohsen Afshin