Uwzględnij kilka odniesień na drugim poziomie

88

Załóżmy, że mamy ten model:

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

i

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

Z EF7 chciałbym pobrać wszystkie dane z tabeli Tiers, z danymi z tabeli Contact, z tabeli Titre, z tabeli TypeContact i tak dalej ... za pomocą jednej instrukcji. Z Include / ThenInclude API mogę napisać coś takiego:

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

Ale po właściwości Titre nie mogę dołączyć innych referencji, takich jak TypeContact, Langue, Fonction ... Metoda Include sugeruje obiekty Tiers, a ThenInclude sugeruje obiekt Titre, ale nie obiekt Contact. Jak mogę dołączyć wszystkie referencje z mojej listy kontaktów? Czy możemy to osiągnąć za pomocą jednej instrukcji?

Christophe Gigax
źródło

Odpowiedzi:

154

.ThenInclude()będzie łączyć z ostatnim .ThenInclude()lub ostatnim .Include()(w zależności od tego, który jest późniejszy), aby przyciągnąć wiele poziomów. Aby uwzględnić wiele rodzeństwa na tym samym poziomie, użyj innego .Include()łańcucha. Właściwe sformatowanie kodu może znacznie poprawić czytelność.

_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.
bricelam
źródło
3
Przy okazji, to pytanie zainspirowało mnie do stworzenia numeru 2124
bricelam
dlaczego nie: var contacts = _dbSet.Include(tiers => tiers.Contacts); contacts.ThenInclude(contact => contact.Titre); contacts.ThenInclude(contact => contact.TypeContact); contacts.ThenInclude(contact => contact.Langue); czy to nie zadziała?
Doug
1
@Doug Nie, za Queryablekażdym razem tworzysz nowe obiekty i nigdy ich nie oceniasz . contactsmiałby tylko oryginalną wartość, którą mu przypisałeś.
bricelam
a co jeśli tiers.Contactsjest List<T>? jak określiłbyś przedmiot?
shashwat
2
To rozwiązanie działa, ale wynikowa instrukcja SQL powoduje trzy LEFT JOIN z Kontaktami (przynajmniej z mojego doświadczenia). To jest strasznie nieefektywne. Musi być lepszy sposób.
EL MOJO
7

Ze względu na kompletność:

Możliwe jest również dołączenie zagnieżdżonych właściwości bezpośrednio przez, Include jeśli nie są one właściwościami kolekcji, jak na przykład:

_dbSet
    .Include(tier => tier.Contact.Titre)
    .Include(tier => tier.Contact.TypeContact)
    .Include(tier => tier.Contact.Langue);
Risadinha
źródło