Метод LINQ для загрузки дочернего объекта, который включает некоторые навигационные свойства Parent и только выбранные записи Grand Child - PullRequest
0 голосов
/ 03 мая 2019

У меня есть три таблицы Site_Report Report_Asset и Asset_Calcert с отношением один-ко-многим между ними, как показано.

Relationship diagram

Я хочу загрузить дочернюю сущность как модель, т.е. Report_Asset, которая должна включать некоторые свойства родителя.А также, из свойства навигации коллекции большого ребенка я хочу загрузить одну запись, используя условие.

Первая попытка - это приводит к ошибке.

Report_Asset model;
model = ctx.Report_Asset
           .Include(i => i.Site_Report)
           .Include(i => i.Site_Report.Handled_By)
           .Include(i => i.Site_Report.Published_By)
           .Include(i => i.Asset_Calcerts.Select(b => b.asset_calcert_id == assetCalcertId))
           .FirstOrDefault();

ОШИБКА: Выражение «Включить путь» должно ссылаться на свойство навигации, определенное для типа.Используйте пунктирные пути для ссылочных навигационных свойств и оператор Select для навигационных свойств коллекции.

Вторая попытка - начиная с внука формы Entity и включая его родителей.Этот подход загружает результирующий набор, но он содержит только дочернюю сущность, т.е. Report_Asset и не содержит записей из Asset_Calcert collection и null для Site_Report.

Report_Asset model;
model = ctx.Asset_Calcert.Include(i => i.Report_Asset)
                                 .Include(i => i.Report_Asset.Site_Report.Handled_By)
                                 .Include(i => i.Report_Asset.Site_Report.Published_By)
                                 .Where(i => i.asset_calcert_id == assetCalcertId)
                                 .Select(i => i.Report_Asset).FirstOrDefault();

У меня установлено Configuration.LazyLoadingEnabled = falseв DbContext ().

Нужно направление, спасибо

Ответы [ 2 ]

2 голосов
/ 03 мая 2019

Похоже, что вы хотите запросить и вернуть сущность, ее родителя, а затем подмножество его дочерних элементов.Вы можете использовать EF для запроса этого, но только уменьшив ваш запрос до желаемой структуры.Если вы возвращаете Report_Asset, он может достаточно легко включить ссылку на своего родителя, но он всегда будет ссылаться на свой полный набор дочерних элементов, EF не фильтрует дочерние наборы на уровне сущности.

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

var model = ctx.Report_Asset
    .Select( x = > new 
    {
       Report_Asset = x,
       Site_Report = x.Site_Report,
       Handled_By = x.Site_Report.Handled_By,
       Published_By = x.Site_Report.Published_By,
       Asset_Calcerts = x.Assert_Calcerts.Where(c => c.asset_calcert_id == assetCalcertId).ToList()
    }).FirstOrDefault();

Проверка calcert выглядит как поиск определенногоодин сертификат, так что это может быть лучше:

var model = ctx.Report_Asset
    .Select( x = > new 
    {
       Report_Asset = x,
       Site_Report = x.Site_Report,
       Handled_By = x.Site_Report.Handled_By,
       Published_By = x.Site_Report.Published_By,
       Asset_Calcert = x.Assert_Calcerts.SingleOrDefailt(c => c.asset_calcert_id == assetCalcertId)
    }).FirstOrDefault();

Если вы хотели загружать только активы отчета, которые имели соответствующий Calcert, с родительским элементом и соответствующим calcert:

var model = ctx.Report_Asset
    .Where(x => x.Asset_Calcerts.Any(c => c.asset_calcert_id == assetCalcertId))
    .Select( x = > new 
    {
       Report_Asset = x,
       Site_Report = x.Site_Report,
       Handled_By = x.Site_Report.Handled_By,
       Published_By = x.Site_Report.Published_By,
       Asset_Calcert = x.Asset_Calcerts.SingleOrDefailt(c => c.asset_calcert_id == assetCalcertId)
    }).FirstOrDefault();

Во всех случаях я бы рекомендовал добавить предложение OrderBy перед FirstOrDefault, чтобы обеспечить использование предсказуемого порядка.

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

model.Report_Asset.Asset_Calcerts

, например, это все равно будет лениво загружать связанные сущности для этого актива отчета, и перечислять все калькуляторы для этого актива,Отфильтрованный набор / совпадение загружен в модель. Asset_Calcert (s), а не возвращенная сущность Model_Asset.

Как правило, вам лучше использовать Select, чтобы просто получить нужные вам свойства из различныхобъекты, а не пытаться выбрать целые объекты или графы объектов.Это исключает необходимость использования Include, просто скажите EF, что именно вы хотите от графа сущностей, и он создаст оператор SQL для эффективного извлечения только этой информации.

0 голосов
/ 03 мая 2019

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

Report_Asset model;
model = ctx.Report_Asset
           .Include("Site_Report")
           .Include("Site_Report.Handled_By")
           .Include("Site_Report.Published_By")
           .Include("Asset_Calcerts")
           .FirstOrDefault(x => x.Asset_Calcerts.Any(y => y.asset_calcert_id == assetCalcertId);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...