Includere diversi riferimenti al secondo livello


93

Supponiamo di avere questo modello:

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

Con EF7 vorrei recuperare tutti i dati dalla tabella Tiers, con i dati dalla tabella Contact, dalla tabella Titre, dalla tabella TypeContact e così via ... con una sola istruzione. Con Include / ThenInclude API posso scrivere qualcosa del genere:

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

Ma dopo la proprietà Titre, non posso includere altri riferimenti come TypeContact, Langue, Fonction ... Il metodo Include suggerisce un oggetto Tiers e ThenInclude suggerisce un oggetto Titre, ma non un oggetto Contact. Come posso includere tutti i riferimenti dal mio elenco di contatti? Possiamo raggiungere questo obiettivo con una singola istruzione?

Risposte:


163

.ThenInclude()verrà concatenato dall'ultimo .ThenInclude()o dall'ultimo .Include()(a seconda di quale sia il più recente) per inserire più livelli. Per includere più fratelli allo stesso livello, usa semplicemente un'altra .Include()catena. La formattazione del codice corretto può migliorare drasticamente la leggibilità.

_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
A proposito, questa domanda mi ha ispirato a creare il numero 2124
bricelam

perché no: var contacts = _dbSet.Include(tiers => tiers.Contacts); contacts.ThenInclude(contact => contact.Titre); contacts.ThenInclude(contact => contact.TypeContact); contacts.ThenInclude(contact => contact.Langue); non funzionerebbe?
Doug

1
@Doug No, creeresti Queryableogni volta nuovi oggetti e non li valuteresti mai. contactsavrebbe sempre e solo il valore originale che gli hai assegnato.
bricelam

2
Questa soluzione funziona ma l'istruzione SQL risultante si traduce in tre LEFT JOIN con i contatti (almeno nella mia esperienza). Questo è terribilmente inefficiente. Deve esserci un modo migliore.
EL MOJO

3
Per i nuovi cercatori: nel 2020, con EF Core 3.1, il mio test con la soluzione accettata ha funzionato bene e non ha portato a 3 join rimasti.
heringer

8

Per completezza:

È anche possibile includere proprietà annidate direttamente tramite Include nel caso in cui non siano proprietà di raccolta in questo modo:

_dbSet
    .Include(tier => tier.Contact.Titre)
    .Include(tier => tier.Contact.TypeContact)
    .Include(tier => tier.Contact.Langue);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.