2011-01-31 14 views
9

tengo un método:¿El uso de una expresión lambda pasada a un método ralentiza una consulta de Entity Framework?

public static void GetObjects() 
{ 
    using(MyContext context = new MyContext()) 
    { 
     var objects = context.Bars.Where(b => b.Prop1 != null) 
         .Select(b => new MyObject{Prop = b.Prop1, Name = b.Name}) 
         .ToList(); 
     foreach(var object in objects) 
     { 
      // do something with the object 
     } 
    } 
} 

I refactorizado el método para hacerlo más general, de modo que pueda pasar en un Func para que pueda especificar la declaración where y qué propiedad de la mesa Bars se asigna a MyObject.Prop de esta manera:

public static void GetObjectsV2(Func<Bar, bool> whereFunc, Func<Bar, string> selectPropFunc) 
{ 
    using(MyContext context = new MyContext()) 
    { 
     var objects = context.Bars.Where(whereFunc) 
         .Select(b => new MyObject{Prop = selectPropFunc(b), Name = b.Name}) 
         .ToList(); 
     foreach(var object in objects) 
     { 
      // do something with the object 
     } 
    } 
} 

GetObjectsV2 parece funcionar mucho más lento que GetObjects. ¿Hay alguna razón por la cual esto afectaría el rendimiento? De ser así, ¿hay alguna forma de evitar esto y mantener la función flexible?

Respuesta

16

La razón por la que se ejecuta más despacio es porque está pasando un Func<Bar, bool> que fuerza al contexto a recuperar TODAS las barras y luego ejecutar el Func en el conjunto de resultados devuelto. Una manera de hacer esto funcione mejor es pasar en Expression<Func<Bar, bool>>

Poner que en su conjunto tendrá como resultado lo siguiente:

public static void GetObjectsV2(Expression<Func<Bar, bool>> whereFunc, Expression<Func<Bar, string>> selectPropFunc) 
{ 
    using(MyContext context = new MyContext()) 
    { 
     var objects = context.Bars.Where(whereFunc) 
         .Select(selectPropFunc) 
         .ToList(); 
     foreach(var object in objects) 
     { 
      // do something with the object 
     } 
    } 
} 
+0

Muchas gracias por la respuesta rápida! – aubreyrhodes

5

Como I discovered in my own question, .Where(o => whereFunc(o)) no es lo mismo que .Where(whereFunc) en el marco de la entidad.

El primero, .Where(Expression<Func<Bar, bool>>) funciona como cualquier otra llamada de linq, simplemente agregando la expresión al árbol de expresiones.

En el segundo caso, .Where(Func<Bar, bool>>), compilará y evaluará la llamada a linq (que hasta ahora es solo context.Bars) antes de aplicar el predicado whereFunc.


lo tanto, para responder a su pregunta, el segundo es mucho más lento, ya que está tirando toda la tabla Bars en la memoria antes de hacer nada con él. Usando .Where(o => whereFunc(o)) lugar que debe fijar

(o, como sugiere Marcos, cambiar el tipo de whereFunc a Expression<Func<Bar, bool>>, que Func<Bar, bool> es convertir implícitamente a)

Cuestiones relacionadas