EF LINQ включает несколько и вложенные объекты

Хорошо, у меня есть трехуровневые объекты со следующей иерархией: Курс → Модуль → Глава

Вот исходный оператор EF LINQ:

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

Теперь я хочу включить другой объект под названием Lab, который связан с курсом.

Как включить объект Lab?

Я пробовал следующее, но это не сработало:

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

Любые идеи о включении второго объекта?

Любая рекомендация или информация будут высоко оценены. Спасибо!

Ответ 1

Вы пробовали просто добавить еще один Include:

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

Ваше решение не работает, потому что Include не принимает логический оператор

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

Обновление Чтобы узнать больше, загрузите LinqPad и просмотрите образцы. Я думаю, что это самый быстрый способ познакомиться с Линком и Лямбдой.

В начале - разница между Select и Include заключается в том, что с помощью Select выберите , что, которое вы хотите вернуть (aka projection). Include - это функция Eager Loading, которая сообщает Entity Framework, что вы хотите, чтобы она включала данные из других таблиц.

Синтаксис Include также может быть в строке. Вот так:

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

Но образцы в LinqPad объясняют это лучше.

Ответ 2

Include является частью свободного интерфейса, поэтому вы можете писать несколько операторов Include, которые следуют за другими

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

Ответ 3

Вы также можете попробовать

db.Courses.Include("Modules.Chapters").Single(c => c.Id == id);

Ответ 4

В EF.core вы можете использовать .ThenInclude для включения следующих уровней.

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

Дополнительная информация: https://docs.microsoft.com/en-us/ef/core/querying/related-data

Ответ 5

Можно написать способ расширения следующим образом:

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

И используйте его так же, как в общей реализации:

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

var query = context.Set<T>()
.Include(includedNavigationProperties);