2010-07-28 13 views
131

Esto puede ser una pregunta realmente elemental, pero ¿cuál es una buena manera de incluir entidades múltiples hijos al escribir una consulta que abarca TRES niveles (o más)?Entidad framework linq query Include() entidades múltiples hijos

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

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

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

si quiero escribir una consulta que devuelve los datos de todas las tablas 4, actualmente estoy escribiendo:

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

Tiene que haber una forma más elegante! Esto es prolijo y genera SQL horrendo

estoy usando EF4 con VS 2010

Respuesta

163

Uso extension methods. 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) ; 
     } 

} 

A continuación, el código se convierte en

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

    //or if you want even more 
    Company company = 
      context.CompanyById(companyID); 
+5

esto es increíble. –

+0

Pero me gustaría usarlo como este: '// dentro de las extensiones de clase public static públicas estáticas IQueryable CompleteCompanies (esta tabla DbSet ) { mesa de retorno .include ("Employee.Employee_Car") .include (" Employee.Employee_Country "); } // código será ... Compañía de la compañía = context.Companies.CompleteCompanies(). FirstOrDefault (c => c.Id == companyID); // igual para el próximo método avanzado' – Hamid

+0

Bullsye Nix. Las extensiones deberían ser el primer puerto de escala para ... bueno ... extender la funcionalidad predefinida. – ComeIn

24

Usted 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 varias tablas en forma de formas de gráfico declarativas.

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.

+1

¡Artículo muy interesante! –

91

EF 4,1 a EF 6

Hay una strongly typed .Include que permite que la profundidad requerida de la carga ansioso de ser especificado por proporcionar Seleccione expresiones a la profundidad apropiada:

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 ambas instancias todavía no son intuitivas, pero parecen lo suficientemente efectivas.He poner un pequeño ejemplo en GitHub here

EF Core

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

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

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

información obsoleta (no hacerlo):

Las múltiples nietos carga podrían hacerse en un solo paso, pero esto requiere una inversión bastante incómodo copia de seguridad de la gráfica antes de dirigirse al siguiente nodo (Nota: esto no funciona con AsNoTracking() - obtendrá un error 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 (uno Incluir por hoja modelo de profundidad entidad).

+3

Me preguntaba cómo hacerlo con sentencias .Include fuertemente tipadas. ¡Proyectar a los niños con Select fue la respuesta! –

+6

Gracias por agregar el espacio de nombre. – GRGodoi

+1

Mi equivalente de "co.Employees.Select (...)" muestra un error de sintaxis en "Seleccionar", diciendo que "'Empleados' no contiene una definición para 'Seleccionar' [o método de extensión]". He incluido System.Data.Entity. Solo quiero obtener una sola columna de la tabla unida. –

Cuestiones relacionadas