Entity Framework - включает несколько уровней свойств

Метод Include() отлично работает для списков объектов. Но что, если мне нужно идти на два уровня в глубину? Например, приведенный ниже метод вернет ApplicationServers с включенными свойствами, показанными здесь. Однако ApplicationWithOverrideGroup - это еще один контейнер, содержащий другие сложные объекты. Могу ли я использовать Include() для этого свойства? Или как я могу получить это свойство для полной загрузки?

Как сейчас, этот метод:

public IEnumerable<ApplicationServer> GetAll()
{
    return this.Database.ApplicationServers
        .Include(x => x.ApplicationsWithOverrideGroup)                
        .Include(x => x.ApplicationWithGroupToForceInstallList)
        .Include(x => x.CustomVariableGroups)                
        .ToList();
}

Будет заполнено только свойство Enabled (ниже), а не свойства Application или CustomVariableGroup (ниже). Как это сделать?

public class ApplicationWithOverrideVariableGroup : EntityBase
{
    public bool Enabled { get; set; }
    public Application Application { get; set; }
    public CustomVariableGroup CustomVariableGroup { get; set; }
}

Ответ 1

Для EF 6

using System.Data.Entity;

query.Include(x => x.Collection.Select(y => y.Property))

Обязательно добавьте using System.Data.Entity;, чтобы получить версию Include, которая принимает лямбду.


Для EF Core

Используйте новый метод ThenInclude

query.Include(x => x.Collection)
     .ThenInclude(x => x.Property);

Ответ 2

Если я правильно вас понимаю, вы спрашиваете о включении вложенных свойств. Если да:

.Include(x => x.ApplicationsWithOverrideGroup.NestedProp)

или

.Include("ApplicationsWithOverrideGroup.NestedProp")  

или

.Include($"{nameof(ApplicationsWithOverrideGroup)}.{nameof(NestedProp)}")  

Ответ 3

EF Core: Использование "ThenInclude" для загрузки нескольких уровней: Например:

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

Ответ 4

Я сделал небольшой помощник для Entity Framework 6 (стиль .Net Core), чтобы включить в него дочерние объекты.

Сейчас на NuGet: Install-Package ThenInclude.EF6

using System.Data.Entity;

var thenInclude = context.One.Include(x => x.Twoes)
    .ThenInclude(x=> x.Threes)
    .ThenInclude(x=> x.Fours)
    .ThenInclude(x=> x.Fives)
    .ThenInclude(x => x.Sixes)
    .Include(x=> x.Other)
    .ToList();

Пакет доступен на GitHub.

Ответ 5

Мне также пришлось использовать несколько включений, а на 3-м уровне мне нужно было несколько свойств

(from e in context.JobCategorySet
                      where e.Id == id &&
                            e.AgencyId == agencyId
                      select e)
                      .Include(x => x.JobCategorySkillDetails)
                      .Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt.DurationType))
                      .Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt.RuleType))
                      .Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt.RateType))
                      .FirstOrDefaultAsync();

Это может помочь кому-то:)

Ответ 6

Другие примеры EFCore на MSDN показывают, что вы можете делать довольно сложные вещи с Include и ThenInclude.

Это хороший пример того, насколько сложным вы можете стать (это все одно утверждение!):

viewModel.Instructors = await _context.Instructors

      .Include(i => i.OfficeAssignment)

      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Enrollments)
                .ThenInclude(i => i.Student)

      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Department)

      .AsNoTracking()
      .OrderBy(i => i.LastName)
      .ToListAsync();

Посмотрите, как вы можете связать Include даже после ThenInclude, и это как бы "сбрасывает" вас обратно на уровень сущности верхнего уровня (Инструкторы).

Вы даже можете повторять одну и ту же коллекцию "первого уровня" (CourseAssignments) несколько раз, а затем использовать отдельные команды ThenIncludes для перехода к различным дочерним объектам.

Обратите внимание, что ваш фактический запрос должен быть помечен в конце цепочки Include или ThenIncludes. Следующее НЕ работает:

var query = _context.Instructors.AsQueryable();
query.Include(i => i.OfficeAssignment);

var first10Instructors = query.Take(10).ToArray();

Настоятельно рекомендую настроить ведение журнала и убедиться, что ваши запросы не вышли из-под контроля, если вы включаете более одной или двух вещей. Важно увидеть, как это работает на самом деле - и вы заметите, что каждое отдельное "включение" обычно является новым запросом, чтобы избежать массивных объединений, возвращающих избыточные данные.

AsNoTracking может значительно ускорить процесс, если вы не собираетесь на самом деле редактировать объекты и сохранять их.

Ответ 7

Позвольте мне четко заявить, что вы можете использовать перегрузку строки для включения вложенных уровней независимо от кратности соответствующих отношений, если вы не возражаете против использования строковых литералов:

query.Include("Collection.Property")