2012-01-23 6 views
9

Estoy usando Entity Framework de Microsoft como ORM y me pregunto cómo resolver el siguiente problema. Quiero obtener un número de objetos Product de la colección Products donde el Product.StartDate es mayor que el día de hoy. (Esta es una versión simplificada de todo el problema.)¿Por qué el analizador LINQ de EntityFramework maneja un predicado definido externamente de manera diferente?

Actualmente uso:

var query = dbContext.Products.Where(p => p.StartDate > DateTime.Now); 

Cuando se ejecuta esto, después de usar ToList() por ejemplo, en consulta, funciona y el SQL creada es efectiva:

SELECT * FROM Product WHERE StartDate > (GetDate()); 

Sin embargo, quiero mover el predicado de una función para una mejor capacidad de mantenimiento, por lo que he intentado esto:

private Func<Product, bool> GetFilter() 
{ 
    Func<Product, bool> filter = p => p.StartDate > DateTime.Now; 
    return filter; 
} 
var query = dbContext.Products.Where(GetFilter()); 

Esto también funciona desde un punto de vista en la medida en código, ya que devuelve el mismo Product set, pero esta vez el SQL creado es análogo a:

SELECT * FROM Product; 

El filtro se mueve desde el SQL Server para el cliente por lo que es mucho menos eficiente.

Así que mis preguntas son:

  • por qué sucede esto, ¿por qué tratar el analizador LINQ estos dos formatos de manera tan diferente?
  • ¿Qué puedo hacer para aprovechar el filtro por separado pero que se ejecute en el servidor?

Respuesta

4

Usted está devolviendo un Func, pero para inyectar el predicado en el SQL, LINQ requiere un árbol de expresión. Debería funcionar si cambia el tipo de devolución de su método (y de su variable local, por supuesto) al Expression<Func<Product, bool>>.

8

Debe usar un Expression<Func<Product, bool>> para que funcione como usted desea. Un simple Func<Product, bool> le dice a LINQ que desea que ejecute el Where en MSIL en su programa, no en SQL. Es por eso que el SQL está tirando en toda la tabla, luego su código .NET está ejecutando el predicado en toda la tabla.

+0

+1 Just beat me to it. –

+0

@Dommer jaja! ¡Normalmente no soy un buen "sorteo rápido"! –

+1

Gracias, eso funcionó. –

2

Dado que en el segundo caso el filtro func puede ser arbitrario LINQ to EF no puede analizar su filtro en SQL y tiene que resolverlo en el lado del cliente.

+0

De acuerdo, pero esa no puede ser la respuesta completa ya que la expresión en el primer ejemplo podría ser cualquier cosa. Si la función GetFilter se examinara al mismo tiempo que el predicado en línea, entonces no habría ningún problema. ¿Esto significa que el orden de ejecución es diferente? –

Cuestiones relacionadas