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")