Here's how my DataAccessLayer works :
public Foo GetFooBy(Func<Foo, bool> filter)
{
var query = from item in this.DataService.FooSet select item;
var where = query.Where(filter);
var first = where.First();
return first;
}
I assumed the query would be run when First() is called but it's actually executed by the Where(). From the MSDN, I realized that .Where(Func) is an extension method defined by Enumerable, so it makes sense, but I don't understand how is it different from calling .Where() with a lambda expression.
A very easy way to be sure that .Where() materialized the data is to check query's, where's and first's type.
Debug and SQL traces also make it very clear that data is fetched by the .Where()
EDIT : * possibly not true since IQueryable implements IEnumerable
答案 0 :(得分:9)
There is a very important difference between Enumerable.Where
and Queryable.Where
:
Enumerable.Where
takes a Func<T, bool>
.
Queryable.Where
takes an Expression
.
Your filter
variable is not an Expression
, it is a Func<T, bool>
, therefore, the compiler uses Enumerable.Where
.
What happens then is that all rows of your FOO
table are transferred to your client and are then filtered in memory.
As others correctly noted, the execution still happens on the call to First()
.
UPDATE:
Your SQL trace doesn't prove that the materialization happens on the call to Where
. It only proves that the filtering of the Where
is not happening on the server side. And the reason for that is explained in my answer above.
How to fix:
You can easily fix this by changing your method to take an Expression instead:
public Foo GetFooBy(Expression<Func<Foo, bool>> filter)
{
var query = from item in this.DataService.FooSet select item;
var where = query.Where(filter);
var first = where.First();
return first;
}
答案 1 :(得分:0)
I assumed the query would be run when
First()
is called
That's a correct assumption.
but it's actually executed by the
Where()
That's either false, or you're not using a Where
method from System.Linq
.
I don't understand how is it different from calling
Where()
with a lambda expression.
It's not. Well, unless the Queryable.Where
would have been the one executed had you provided a lambda, but in both cases execution would be deferred.
On a side note, your entire method body could be re-written as:
return this.DataService.FooSet.First(filter);
It'd behave identically.