9

I'm using Microsoft's Entity Framework as an ORM and am wondering how to solve the following problem. I want to get a number of Product objects from the Products collection where the Product.StartDate is greater than today. (This is a simplified version of the whole problem.)

I currently use:

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

When this is executed, after using ToList() for example on query, it works and the SQL created is effectively:

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

However, I want to move the predicate to a function for better maintainability, so I tried this:

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

This also works from a code point of view insofar as it returns the same Product set but this time the SQL created is analogous to:

SELECT * FROM Product;

The filter is moved from the SQL Server to the client making it much less efficient.

So my questions are:

  • Why is this happening, why does the LINQ parser treat these two formats so differently?
  • What can I do to take advantage of having the filter separate but having it executed on the server?
Kamil Budziewski
  • 22,699
  • 14
  • 85
  • 105
Joe Fawcett
  • 307
  • 2
  • 7

3 Answers3

8

You need to use an Expression<Func<Product, bool>> in order for it to work like you intend. A plain Func<Product, bool> tells LINQ that you want it to run the Where in MSIL in your program, not in SQL. That's why the SQL is pulling in the whole table, then your .NET code is running the predicate on the entire table.

Andrew Barber
  • 39,603
  • 20
  • 94
  • 123
4

You are returning a Func, but to inject the predicate into the SQL, LINQ requires an expression tree. It should work if you change the return type of your method (and of your local variable, of course) to Expression<Func<Product, bool>>.

Nuffin
  • 3,882
  • 18
  • 34
2

Since in second case filter func maybe arbitrary LINQ to EF can't parse you filter to SQL and has to resolve it on client side.

Vitaliy Kalinin
  • 1,791
  • 12
  • 20
  • Agreed, but that can't be the whole answer as the expression in the first example could be anything too. If the GetFilter function were examined at the same time as the inline predicate was then there would be no problem. Does this mean the order of execution is different? – Joe Fawcett Jan 23 '12 at 09:26