Entity Framework - включає декілька рівнів властивостей


376

Метод Include () працює досить добре для списків об’єктів. Але що робити, якщо мені потрібно пройти два рівні глибоко? Наприклад, наведений нижче метод поверне ApplicationServers з включеними тут властивостями. Однак ApplicationsWithOverrideGroup - це ще один контейнер, який містить інші складні об'єкти. Чи можу я також включити () на цю властивість? Або як я можу змусити цю властивість повністю завантажити?

Як зараз, цей метод:

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

Привіт, Чому я отримую виняток Expression must be a member expressionпри спробі це: Для того, щоб включати в себе колекцію , а потім рівень збору один вниз: query.Include(e => e.Level1Collection.Select(l1 => l1.Level2Collection)).
Joe.wang

1
@BobHorn, у мене те саме питання .. У моєму випадку гніздування проходить в глибині декількох шарів, мені вдалося зробити включене вами вказане. У створеному SQL я міг бачити, що всі стовпці повертаються з різним ім'ям псевдоніму як c1, c2 щось подібне. Моє запитання полягає в тому, як я можу сформувати вкладену колекцію DTO з усіх моїх включень :( .. Можливо, ви можете взяти сам наведений вище приклад, оскільки ми повертаємо всі стовпці без будь-якого користувальницького DTO (який сам є колекцією DTO )
TechQuery

Відповіді:


703

Для 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);

1
Я не можу включати () у програму ApplicationsWithOverrideGroup. Це не відображається в інтелігенції.
Боб Хорн

Я не можу використовувати ваше редагування, оскільки ApplicationsWithOverrideGroup - це список. Додаток - це властивість кожного елемента в списку, а не самого списку.
Боб Горн

1
Аааааа, але це посилання, яке ви надали, здається, дає відповідь. Дозвольте мені спробувати це: Щоб включити колекцію, а потім колекцію на один рівень вниз: query.Include (e => e.Level1Collection.Select (l1 => l1.Level2Collection)).
Боб Хорн

60
Не забудьте включити System.Data.Entity у звички. Інакше Intellisense надасть лише версію методу Включити (рядок).
OJ Raqueño

5
@Adeem вам потрібно зателефонувати Includeдля кожного готелю:Db.States.Include(state => state.Cities.Select(city => city.Customers).Include(state => state.Cities.Select(city => city.Vendors)
Дієго Торрес

72

Якщо я правильно вас зрозумів, ви запитуєте про включення вкладених властивостей. Якщо так :

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

або

.Include("ApplicationsWithOverrideGroup.NestedProp")  

або

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

6
Дякую, я можу спробувати це. Я сподівався, що зможу тримати речі, які сильно набираються, і уникати рядкових букв. Але якщо так треба зробити ...
Боб Хорн

1
Ви були поруч. Можливо, мені не було зрозуміло, що ApplicationsWithOverrideGroup - це список. Дякуємо за допомогу!
Боб Хорн

@ Джудо, у мене те саме питання .. У моєму випадку гніздування проходить вглиб декількох шарів, мені вдалося зробити включення, на яке ви вказали. У створеному SQL я міг бачити, що всі стовпці повертаються з різним ім'ям псевдоніму як c1, c2 щось подібне. Моє запитання полягає в тому, як я можу сформувати вкладену колекцію DTO з усіх моїх включень :( .. Можливо, ви можете взяти сам наведений вище приклад, оскільки ми повертаємо всі стовпці без будь-якого користувальницького DTO (який сам є колекцією DTO )
TechQuery

2
Не забудьте включити System.Data.Entity у звички. Інакше Intellisense надасть лише Include(string path)версію методу.
AlexMelw

52

EF Core: Використання "thenInclude" для завантаження рівнів безперервної дії: Наприклад:

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

53
Схоже, це лише EF Core
Кріс Марісіч,

27
FYI: VS2017 інтелігенція не працювала. ThenInclude. Просто введіть його так, як ви думаєте, як це має бути, і виділення помилок повинне піти.
JohnWrensby

4
Я хочу наголосити на коментарі @JohnWrensby, що Intellisense іноді може зайняти дуже багато часу, щоб обробити ці події потім, це може бути дуже заплутано для нових користувачів. У мене також були випадки, коли простий вираз лямбда-виразу не був оброблений належним чином, поки ви просто не введете його і не скомпілюєте, ігноруючи "помилки", показані у VS.
Pac0

@ Pac0 ти врятував мені день. з усіх сил намагався побачити предмети дитини і не міг.
Бендрам

28

Я зробив невеличку допомогу для Entity Framework 6 (стиль .Net Core), щоб приємно включати суб-об'єкти.

Зараз на NuGet: Install-Package OndaInclude.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 .


привіт, у мене є виняток під час виконання, я не можу передавати IncludableQueyable <observablecollection> у IncludableQueyable <genericcollection>
user2475096

Спочатку я використовую db, і я змінив файл tt, щоб отримати ObservableCollections для всіх моїх організацій, будь-яка допомога вітається.
користувач2475096

2
@ lenny32 що-небудь слід знати про це розширення?
Аарон Гудон

Зауважте, що це не потрібно, якщо властивість, за якою ви переходите, однозначно з DbSet, з якого ви переходили, і ви можете зв'язати DbSet<One>().Include(x => x.Two.Three.Four.Five.Six)єдиний недолік, який ви обчислюєте декартовим продуктом і потенційно збільшуєте пропускну здатність.
Іван Заброський

23

Більше прикладів 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 може значно пришвидшити ситуацію, якщо ви не збираєтесь фактично редагувати об'єкти та ремонтувати.


Чи є спосіб отримати як зарахування, так і кафедри без повторного включення. Включає курси присвоєння та курсу? (Поки здається, що Api може заглибитись .ThenInclude, або повернутися до вищого рівня за допомогою. Включити, але нічого не залишатись на тому ж рівні?)
Вільям Йокуш

Якщо ви хочете ліниво завантажуватись, налаштовуйтесь на блог EF Core 2.1 . Я не впевнений, що ви думаєте - для цього не потрібно багато зайвих, і це значно зменшує те, що повертається з бази даних. У суб'єкта господарювання може бути один або два речі "одного рівня", але він також може мати 50 для великого проекту, оскільки явний процес робить ваш додаток набагато швидшим.
Simon_Weaver

Це було гарним поясненням концепції включити "перезавантаження" рівня знову до початкового рівня. Допоміг мені обернути голову навколо спадкоємності системи включеного. Ура!
AFM-Horizon

22

Я також повинен був використовувати кілька включень, і на 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();

Це може допомогти комусь :)


1
чи можна це зробити, не повторюючись.Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt......
Multinerd

ну це залежить, наскільки глибоко ви хочете піти
dnxit

7

Дозвольте мені чітко зазначити, що ви можете використовувати перевантаження рядків для включення вкладених рівнів незалежно від кратності відповідних зв’язків, якщо ви не заперечуєте з використанням рядкових літералів:

query.Include("Collection.Property")

1
Цей метод був корисним для мене, щоб зрозуміти, як це можна кодувати у VB, оскільки я не можу знайти десь після годин гуглінгу.
Кодер

Це чудово працює для мене, я цим багато користуюся !!! Це навіть працює в поєднанні з .SelectMany заявами:query.SelectMany(x=>x.foos).Include("bar").Include("bar.docs")...
Ефі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.