Entité cadre linq interrogation Include () multiple children entities

C'est peut-être une question vraiment élémentaire, mais quelle est une bonne façon d'inclure plusieurs entités enfants lors de l'écriture d'une requête qui s'étend sur trois niveaux (ou plus)?

i.e. j'ai 4 tables: Company , Employee , Employee_Car et Employee_Country

société a une relation 1: m avec L'employé.

L'employé

a une relation 1: m à la fois avec Employee_Car et Employee_Country.

Si je veux ecrire une requête qui renvoie les données des 4 tables, je suis en train d'écrire:

Company company = context.Companies
                         .Include("Employee.Employee_Car")
                         .Include("Employee.Employee_Country")
                         .FirstOrDefault(c => c.Id == companyID);

il doit y avoir une façon plus élégante! Il s'agit d'un long coup de vent et génère D'horribles SQL

j'utilise EF4 avec VS 2010

147
demandé sur Mafii 2010-07-28 23:15:00

4 réponses

Utiliser les méthodes d'extension . Remplacer NameOfContext par le nom de votre contexte objet.

public static class Extensions{
   public static IQueryable<Company> CompleteCompanies(this NameOfContext context){
         return context.Companies
             .Include("Employee.Employee_Car")
             .Include("Employee.Employee_Country") ;
     }

     public static Company CompanyById(this NameOfContext context, int companyID){
         return context.Companies
             .Include("Employee.Employee_Car")
             .Include("Employee.Employee_Country")
             .FirstOrDefault(c => c.Id == companyID) ;
      }

}

puis votre code devient

     Company company = 
          context.CompleteCompanies().FirstOrDefault(c => c.Id == companyID);

     //or if you want even more
     Company company = 
          context.CompanyById(companyID);
179
répondu Nix 2012-10-22 17:03:03

EF 4.1 à EF 6

il y a un fortement dactylographié .Include qui permet de spécifier la profondeur de chargement requise en fournissant des expressions sélectives à la profondeur appropriée:

using System.Data.Entity; // NB!

var company = context.Companies
                     .Include(co => co.Employees.Select(emp => emp.Employee_Car))
                     .Include(co => co.Employees.Select(emp => emp.Employee_Country))
                     .FirstOrDefault(co => co.companyID == companyID);

le Sql généré dans les deux cas est encore loin d'être intuitif, mais semble suffisamment performant. J'ai mis un petit exemple sur GitHub ici

EF de Base

EF Core a une nouvelle méthode d'extension, .ThenInclude() , bien que la syntaxe soit légèrement différent :

var company = context.Companies
                     .Include(co => co.Employees)
                           .ThenInclude(emp => emp.Employee_Car)
                      ...

D'après le docs, je garderais le "tiret" supplémentaire dans le .ThenInclude pour préserver votre santé mentale.

Obsolète Info (Ne pas faire):

le multiple petit-enfants chargement pourrait être fait en une seule étape, mais cela nécessite une inversion assez maladroite sauvegarder le graphe avant de descendre le prochain noeud (NB: cela ne fonctionne pas avec AsNoTracking() - vous obtiendrez une erreur d'exécution):

var company = context.Companies
         .Include(co => 
             co.Employees
                .Select(emp => emp.Employee_Car
                    .Select(ec => ec.Employee)
                    .Select(emp2 => emp2.Employee_Country)))
         .FirstOrDefault(co => co.companyID == companyID);

donc je resterais avec la première option (Un modèle de profondeur D'entité Include per leaf).

118
répondu StuartLC 2017-11-13 15:28:51

vous pourriez trouver cet article d'intérêt qui est disponible à codeplex.com .

L'article présente une nouvelle façon d'exprimer les requêtes qui couvrent plusieurs tables sous la forme de graphes déclaratifs.

de plus, l'article contient une performance complète comparaison de cette nouvelle approche avec les requêtes EF. Cette analyse montre que GBQ dépasse rapidement les requêtes EF.

26
répondu Merijn 2011-08-30 07:05:03

comment construire un LINQ pour les entités requête pour charger des objets enfant directement, au lieu d'appeler une propriété de référence ou de charger ()

il n'y a pas d'autre solution - sauf la mise en œuvre de chargement paresseux.

ou chargement manuel....

myobj = context.MyObjects.First();
myobj.ChildA.Load();
myobj.ChildB.Load();
...
6
répondu Andreas Rehm 2017-05-23 12:18:14