working when tables not multiple framework first code linq entity-framework lazy-loading

when - Entidad framework linq query Include() mĂșltiples entidades hijas



linq include vs join (4)

Esta puede ser una pregunta realmente elemental, pero ¿cuál es una buena manera de incluir múltiples entidades secundarias al escribir una consulta que abarca TRES niveles (o más)?

es decir, tengo 4 tablas: Company , Employee , Employee_Car y Employee_Country

La compañía tiene una relación 1: m con el empleado.

El empleado tiene una relación 1: m con Employee_Car y Employee_Country.

Si quiero escribir una consulta que devuelva los datos de las 4 tablas, estoy escribiendo:

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

¡Tiene que haber una manera más elegante! Esto es largo aliento y genera SQL horrendo

Estoy usando EF4 con VS 2010


Puede encontrar este artículo de interés que está disponible en codeplex.com .

El artículo presenta una nueva forma de expresar consultas que abarcan múltiples tablas en forma de formas de gráfico declarativo.

Además, el artículo contiene una comparación exhaustiva del rendimiento de este nuevo enfoque con las consultas de EF. Este análisis muestra que GBQ supera rápidamente las consultas de EF.


Usa métodos de extensión . Reemplace NameOfContext con el nombre del contexto de su objeto.

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

Entonces tu código se convierte

Company company = context.CompleteCompanies().FirstOrDefault(c => c.Id == companyID); //or if you want even more Company company = context.CompanyById(companyID);



EF 4.1 a EF 6

Existe un .Include fuertemente tipado que permite especificar la profundidad requerida de la carga ansiosa proporcionando expresiones Select a la profundidad adecuada:

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

El Sql generado en ambos casos todavía no es intuitivo, pero parece lo suficientemente eficiente. He puesto un pequeño ejemplo en GitHub aquí

EF Core

EF Core tiene un nuevo método de extensión, .ThenInclude() , aunque la sintaxis es ligeramente diferente :

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

De acuerdo con los documentos, mantendría la ''sangría'' adicional en el .ThenInclude para preservar su cordura.

Información obsoleta (no haga esto):

La carga de múltiples nietos se puede hacer en un solo paso, pero esto requiere una reversión bastante torpe para hacer una copia de seguridad del gráfico antes de dirigirse al siguiente nodo (NB: esto NO funciona con AsNoTracking() - obtendrá un error de tiempo de ejecución):

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

Así que me quedaría con la primera opción (un incluir por modelo de profundidad de entidad de hoja).