Fügen Sie auf der zweiten Ebene mehrere Referenzen hinzu

90

Angenommen, wir haben dieses Modell:

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

und

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

Mit EF7 möchte ich alle Daten aus der Tiers-Tabelle abrufen, mit Daten aus der Contact-Tabelle, aus der Titre-Tabelle, aus der TypeContact-Tabelle usw. ... mit einer einzigen Anweisung. Mit der Include / ThenInclude-API kann ich so etwas schreiben:

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

Nach der Titre-Eigenschaft kann ich jedoch keine anderen Referenzen wie TypeContact, Langue, Fonction ... Include-Methode ein Tiers-Objekt vorschlagen, und ThenInclude schlägt ein Titre-Objekt vor, jedoch kein Contact-Objekt. Wie kann ich alle Referenzen aus meiner Kontaktliste aufnehmen? Können wir dies mit einer einzigen Anweisung erreichen?

Christophe Gigax
quelle

Antworten:

159

.ThenInclude()verkettet entweder das letzte .ThenInclude()oder das letzte .Include()(je nachdem, welches aktueller ist), um mehrere Ebenen zu erreichen. Um mehrere Geschwister auf derselben Ebene einzuschließen, verwenden Sie einfach eine andere .Include()Kette. Das richtige Formatieren des Codes kann die Lesbarkeit drastisch verbessern.

_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
quelle
3
Übrigens
warum nicht: var contacts = _dbSet.Include(tiers => tiers.Contacts); contacts.ThenInclude(contact => contact.Titre); contacts.ThenInclude(contact => contact.TypeContact); contacts.ThenInclude(contact => contact.Langue); Würde das nicht funktionieren?
Doug
1
@Doug Nein, Sie würden Queryablejedes Mal neue Objekte erstellen und diese niemals bewerten. contactswürde immer nur den ursprünglichen Wert haben, den Sie ihm zugewiesen haben.
Bricelam
2
Diese Lösung funktioniert, aber die resultierende SQL-Anweisung führt zu drei LEFT JOINs mit Kontakten (zumindest nach meiner Erfahrung). Das ist schrecklich ineffizient. Es muss einen besseren Weg geben.
EL MOJO
1
Für neue Suchende: Im Jahr 2020 funktionierte mein Test mit der akzeptierten Lösung mit EF Core 3.1 einwandfrei und führte nicht zu drei Linksverknüpfungen.
Heringer
8

Der Vollständigkeit halber:

Es ist auch möglich, verschachtelte Eigenschaften direkt über einzuschließen, Include falls es sich nicht um Auflistungseigenschaften wie folgt handelt :

_dbSet
    .Include(tier => tier.Contact.Titre)
    .Include(tier => tier.Contact.TypeContact)
    .Include(tier => tier.Contact.Langue);
Risadinha
quelle