Inclui várias referências no segundo nível


87

Suponha que temos este modelo:

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

e

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

Com EF7 eu gostaria de recuperar todos os dados da tabela Tiers, com dados da tabela Contact, da tabela Titre, da tabela TypeContact e assim por diante ... com uma única instrução. Com a API Include / ThenInclude, posso escrever algo assim:

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

Mas depois da propriedade Titre, não posso incluir outras referências como TypeContact, Langue, Fonction ... O método Include sugere objetos Tiers e ThenInclude sugere um objeto Titre, mas não um objeto Contact. Como posso incluir todas as referências da minha lista de contatos? Podemos conseguir isso com uma única instrução?

Respostas:


153

.ThenInclude()irá acorrentar o último .ThenInclude()ou o último .Include()(o que for mais recente) para puxar em vários níveis. Para incluir vários irmãos no mesmo nível, basta usar outra .Include()corrente. A formatação correta do código pode melhorar drasticamente a legibilidade.

_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.

3
Aliás, essa questão me inspirou a criar a edição nº 2124
bricelam

por que não: var contacts = _dbSet.Include(tiers => tiers.Contacts); contacts.ThenInclude(contact => contact.Titre); contacts.ThenInclude(contact => contact.TypeContact); contacts.ThenInclude(contact => contact.Langue); não funcionaria?
Doug de

1
@Doug Não, você criaria novos Queryableobjetos a cada vez e nunca os avaliaria. contactsteria apenas o valor original que você atribuiu a ele.
bricelam de

e se tiers.Contactsfor um List<T>? como você especificaria o item então?
shashwat

2
Esta solução funciona, mas a instrução SQL resultante resulta em três LEFT JOINs com Contatos (pelo menos na minha experiência). Isso é terrivelmente ineficiente. Tem que haver uma maneira melhor.
EL MOJO

7

Para completar:

Também é possível incluir propriedades aninhadas diretamente via Include , caso não sejam propriedades de coleção, como:

_dbSet
    .Include(tier => tier.Contact.Titre)
    .Include(tier => tier.Contact.TypeContact)
    .Include(tier => tier.Contact.Langue);
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.