I stumbled over some strange LINQ to SQL behaviour - can anybody shed some light on this?
I want to define a lambda expression and use it in my LINQ statement. The follo
Does Table1
refer to the same namespace? In the first example you're querying against the Table1
objects that are directly under dataContext
, in the second example you're querying against the Table1
objects that is a property of the Table2
objects, and in the last example you're using a anonymous function which fix the issue.
I would look up the type of the Table1
objects that is a property of a Table2
object and compare it to a Table1
object that is connected directly to the dataContext
. My guess is that they differ and your lambda expression is using the type of the object that is connected to the dataContext
.
Okay, here's the deal: dataContext.Table1s
is of type IQueryable<T>
. IQueryable<T>
defines Where
and Any
methods that take a predicate of type Expression<Func<T, bool>>
. The Expression<>
wrapper is critical, as this is what allows LINQ to SQL to translate your lambda expression to SQL and execute it on the database server.
However, IQueryable<T>
also includes IEnumerable<T>
. IEnumerable<T>
also defines Where
and Any
methods, but the IEnumerable version takes a predicate of type Func<T, bool>
. Because this is a compiled function and not an expression, it can't be translated to SQL. As a result, this code...
Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table1s.Where(lambda);
...will pull EVERY record out of Table1s
into memory, and then filter the records in memory. It works, but it's really bad news if your table is large.
Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table2s.Where(x => x.Table1s.Any(lambda));
This version has two lambda expressions. The second one, being passed directly into Where
, is an Expression
that includes a reference to a Func
. You can't mix the two, and the error message you're getting is telling you that the call to Any
is expecting an Expression
but you're passing in a Func
.
var result = dataContext.Table2s.Where(x => x.Table1s.Any(y => y.Id > 1000));
In this version, your inner lambda is automatically being converted to an Expression
because that's the only choice if you want your code to be transformed into SQL by LINQ to SQL. In the other cases, you're forcing the lambda to be a Func
instead of an Expression
- in this case you're not, so it works.
What's the solution? It's actually pretty simple:
Expression<Func<Table1, bool>> lambda = x => x.Id > 1000;