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
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);
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).
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.
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();
...