Включите несколько ссылок на втором уровне

Предположим, у нас есть такая модель:

public class Tiers
{
    public List<Contact> Contacts { get; set; }
}

и

public class Contact
{
    public int Id { get; set; }
    public Tiers Tiers { get; set; }
    public Titre Titre { get; set; }
    public TypeContact TypeContact { get; set; }
    public Langue Langue { get; set; }
    public Fonction Fonction { get; set; }
    public Service Service { get; set; }
    public StatutMail StatutMail { get; set; }
}

С EF7 я хотел бы получить все данные из таблицы Tiers, с данными из таблицы Contact, из таблицы Titre, из таблицы TypeContact и так далее ... с помощью одной единственной инструкции. С помощью Include / ThenInclude API я могу написать что-то вроде этого:

_dbSet
     .Include(tiers => tiers.Contacts)
          .ThenInclude(contact => contact.Titre)
     .ToList();

Но после свойства Titre я не могу включать другие ссылки, такие как TypeContact, Langue, Fonction ... Метод Include предлагает объекты Tiers, а ThenInclude предлагает объект Titre, но не объект Contact. Как я могу включить все ссылки из моего списка контактов? Можем ли мы добиться этого с помощью одной-единственной инструкции?


person Christophe Gigax    schedule 06.05.2015    source источник


Ответы (2)


.ThenInclude() будет соединяться либо с последним .ThenInclude(), либо с последним .Include() (в зависимости от того, что будет более поздним), чтобы задействовать несколько уровней. Чтобы включить несколько братьев и сестер на один уровень, просто используйте другую цепочку .Include(). Правильное форматирование кода может значительно улучшить читаемость.

_dbSet
    .Include(tiers => tiers.Contacts).ThenInclude(contact => contact.Titre)
    .Include(tiers => tiers.Contacts).ThenInclude(contact => contact.TypeContact)
    .Include(tiers => tiers.Contacts).ThenInclude(contact => contact.Langue);
    // etc.
person bricelam    schedule 06.05.2015
comment
Кстати, этот вопрос вдохновил меня на создание проблемы # 2124 - person bricelam; 11.05.2015
comment
почему бы и нет: var contacts = _dbSet.Include(tiers => tiers.Contacts); contacts.ThenInclude(contact => contact.Titre); contacts.ThenInclude(contact => contact.TypeContact); contacts.ThenInclude(contact => contact.Langue); Разве это не сработает? - person Doug; 20.05.2016
comment
@Doug Нет, вы каждый раз будете создавать новые Queryable объекты и никогда не оценивать их. contacts будет иметь только исходное значение, которое вы ему присвоили. - person bricelam; 20.05.2016
comment
что, если tiers.Contacts - это List<T>? как бы вы тогда указали товар? - person shashwat; 02.07.2017
comment
Это решение работает, но результирующий оператор SQL приводит к трем ЛЕВЫМ СОЕДИНЕНИЯМ с контактами (по крайней мере, по моему опыту). Это ужасно неэффективно. Там должен быть лучший способ. - person EL MOJO; 26.07.2017
comment
Для новых соискателей: в 2020 году с EF Core 3.1 мой тест с принятым решением работал нормально и не привел к 3 левым соединениям. - person heringer; 26.05.2020

Для полноты:

Также можно напрямую включать вложенные свойства через Include , если они не являются свойствами коллекции, например:

_dbSet
    .Include(tier => tier.Contact.Titre)
    .Include(tier => tier.Contact.TypeContact)
    .Include(tier => tier.Contact.Langue);
person Risadinha    schedule 06.06.2019