EF LINQ obejmuje wiele i zagnieżdżonych jednostek

155

Ok, mam trzypoziomowe encje z następującą hierarchią: Kurs -> Moduł -> Rozdział

Oto oryginalne oświadczenie EF LINQ:

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

Teraz chcę dołączyć inną jednostkę o nazwie Lab, która jest powiązana z kursem.

Jak dołączyć encję Lab?

Próbowałem następujących rzeczy, ale nie zadziałało:

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

Jakieś pomysły na włączenie drugiej jednostki?

Każda rada lub informacja byłaby bardzo mile widziana. Dzięki!

AnimaSola
źródło
1
Dodanie kolejnego .Includepowinno działać, chyba że masz na myśli, że dodatkowe dołączenie jest wnukiem Kursu. Zobacz tę lub lepszą opcję
von v.
Powiązany / możliwy duplikat stackoverflow.com/q/3356541
StuartLC

Odpowiedzi:

234

Czy próbowałeś po prostu dodać kolejny Include:

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

Twoje rozwiązanie zawodzi, ponieważ Includenie wymaga operatora boolowskiego

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

Aktualizacja Aby dowiedzieć się więcej, pobierz LinqPad i przejrzyj próbki. Myślę, że to najszybszy sposób na zapoznanie się z Linq i Lambdą.

Na początek - różnica między Selecti Includepolega na tym, że w przypadku Select decydujesz, co chcesz zwrócić (czyli projekcja). Include to funkcja Eager Loading , która informuje Entity Framework, że chcesz, aby zawierała dane z innych tabel.

Składnia Include może być również w postaci ciągu. Lubię to:

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

Ale próbki w LinqPad wyjaśniają to lepiej.

Jens Kloster
źródło
Doceniam to! Gdzie mogę dowiedzieć się więcej na ten temat? Szczególnie interesuje mnie różnica między Include a Select
AnimaSola
3
Tylko ten pracował dla mnie .Include("Module.Chapter"). Każdy pomysł, dlaczego miałoby to być?
Jo Smo
5
@JoSmo musisz zaimportować przestrzeń nazw, System.Data.Enityaby uzyskać dostęp do metody rozszerzenia. więcej informacji tutaj
Jens Kloster
using System.Data.Entity;zrobił to. Dzięki!
Jo Smo
1
upvoted do wymieniania genialny LINQPad, a wskazówka, aby korzystać System.Data.Entity, thx Jens
Mike
38

W Entity Framework Core ( EF.core) można używać .ThenIncludedo dołączania kolejnych poziomów.

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

Więcej informacji: https://docs.microsoft.com/en-us/ef/core/querying/related-data

Uwaga: powiedz, że potrzebujesz wielu ThenInclude()włączonych blog.Posts, po prostu powtórz Include(blog => blog.Posts)i wykonaj inną 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.
źródło
Wydaje się, że w EF.core nie mogę zrobić .Include (i => i.Modules.Select (s => s.Chapters)), a konkretnie .Select inside .Include. Czy ktoś może potwierdzić lub porozmawiać?
ttugates
@ttugates Co zamierzasz zrobić z tym wyborem? Myślę, że to, co chcesz robić, jest dokładnie tym, co robisz ThenIncludew rdzeniu EF. Może zadaj pytanie z dobrym przykładem, abyśmy mogli na nie odpowiedzieć.
Nick N.
@Nick N - Entity Framework Linq Query: How to Where on Multiple Nav Properties i wybierz z 3rd Nav Property . Ponieważ to, co wybieram, nie jest tym, do czego dopasowuję, dołączenia nie są konieczne, więc pytanie jest styczne. Moje pytanie może być zbyt „wąskie”, ale doceniam każdą pomoc.
ttugates
1
Ach. Właściwie .ThenInclude () działa. IntelliSense zajmuje tylko wieki, aby wyświetlić powiązane tabele.
Chris J
23

Includejest częścią płynnego interfejsu, dzięki czemu można napisać wiele Includeinstrukcji następujących po sobie

 db.Courses.Include(i => i.Modules.Select(s => s.Chapters))
           .Include(i => i.Lab)
           .Single(x => x.Id == id); 
Ilya Ivanov
źródło
doceniam to! czy możesz mi wskazać, gdzie mogę dowiedzieć się więcej na ten temat? Dzięki!
AnimaSola
1
Czy wiesz, jaka jest składnia, jeśli moduły mają wiele tabel, do których chcesz dołączyć? Powiedz, że prowadzi do rozdziałów i czegoś innego?
David Spence,
Czy Fluent jest częścią .Net, czy też jest to biblioteka, którą należy zainstalować?
codea
19

Możesz też spróbować

db.Courses.Include("Modules.Chapters").Single(c => c.Id == id);
Martin Larsson
źródło
4
Dzięki - notacja z kropką w ciągu znaków jest bardzo przydatna
Evert
1
Może to być przydatne, ale jednym z powodów, aby tego nie używać, jest łatwość późniejszej refaktoryzacji: jeśli w pewnym momencie zmienisz nazwę elementu „Rozdziały”, nazwa drugiego przykładu zostanie automatycznie zmieniona. Innym jest to, że błędy zostaną znalezione wcześniej: w czasie kompilacji, a nie w czasie wykonywania.
MGOwen
2

Można napisać taką metodę rozszerzającą:

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

I używaj go w ten sposób nawet w ogólnej implementacji:

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

var query = context.Set<T>()
.Include(includedNavigationProperties);
Mohsen Afshin
źródło
Próbowałem twojej odpowiedzi, ale rzuca ona stosy, przepełnione wyjątkami z powodu nieskończonej pętli ze sobą.
Victoria S.
1
@VictoriaS., Możesz zmienić nazwę metody rozszerzenia, aby nie kolidowała z rzeczywistościąInclude
Mohsen Afshin