views:

136

answers:

2

In my application I'm pulling back a user's "feed". This contains all of that user's activities, events, friend requests from other users, etc. When I pull back the feed I'm calling various functions to filter the request along the way.

        var userFeed = GetFeed(db); // Query to pull back all data
        userFeed = FilterByUser(userFeed, user, db); // Filter for the user
        userFeed = SortFeed(userFeed, page, sortBy, typeName); // Sort it

The data that is returned is exactly what I need, however when I look at a SQL Profile Trace I can see that the query that is getting this data does not filter it at the database level and instead is selecting ALL data in the table(s).

This query does not execute until I iterate through the results on my view. All of these functions return an IEnumerable object.

I was under the impression that LINQ would take all of my filters and form one query to pull back the data I want instead of pulling back all the data and then filtering it on the server.

What am I doing wrong or what don't I understand about the way LINQ evaluates queries?

+4  A: 

If GetFeed returns an IEnumerable, FilterByUser will receive an IEnumerable. When it calls some LINQ operator, i.e. Where, it will use the IEnumerable Where, which will start to ask for information, which will eventually download the entire table. Change the type of GetFeed to IQueryable to make sure that IQueryable's LINQ operators are called instead, which will keep delaying the query.

Jesper
When changing the return type of my functions I get: The entity or complex type 'Feed' cannot be constructed in a LINQ to Entities query.If my understanding of this error is correct, it means all of my filters could not be turned into one query. If that's right, what's the best way to approach this?
Focus
You'll have to select out the information you need to construct the data type into an anonymous class, then perform AsEnumerable() and Select from the anonymous class object to the data type: x.Select(something => new { something.data, something.moreData }).AsEnumerable().Select(wrapped => new Feed(wrapped.data, wrapped.moreData). LINQ to SQL is able to do this automatically even inside queries (it does something like this automatically), so I'm not sure if I'm missing something.
Jesper
Here's the code in question. I believe that the GedFeed method is doing just what you're saying. This is in its original state before I tried to set the return types to IQueryable. http://pastebin.com/R38mWGXH
Focus
Figured it out. Thanks for pointing me in the right direction
Focus
A: 

Can someone explain me the exact reason why .AsEnumerable() in the select query makes possible the construction of an entity type as opposed to NOT use it?

It's all good but I like to know the "why" of things! :)

Thanks!

Stéphan
Because the `Feed` constructor in the last select statement would not be convertible to SQL, you must first select what data you need to be retrieved from the database. The call to ToEnumerable() will execute everything before it in the query, thus pulling the data necessary for `new Feed(...)` to execute in memory. (Note I'm writing this from an NHibernate perspective, but I suspect LinqToSql is similar.)
Ryan
That's correct! I forgot that it was triggering the iteration of the object collection thus, launching the query execution. Makes sense now! Thanks!
Stéphan