views:

99

answers:

3

My project is structured as follows:

DAL

public IQueryable<Post> GetPosts()
{
        var posts = from p in context.Post select p;

        return posts;
}

Service

public IList<Post> GetPosts()
{
        var posts = repository.GetPosts().ToList();

        return posts;
}

//Returns a list of the latest feeds, restricted by the count.
public IList<PostFeed> GetPostFeeds(int latestCount)
{
       List<Post> post - GetPosts();

       //CODE TO CREATE FEEDS HERE

       return feeds;

}

Lets say the GetPostFeeds(5) is supposed to return the 5 latest feeds. By going up the list, doesn't it pull down every single post from the database from GetPosts(), just to extract 5 from it?

If each post is say 5kb from the database, and there is 1 million records. Wont that be 5GB of ram being used per call to GetPostFeeds()?

Is this the way it happens? Should I go back to my DAL and write queries that return only what I need?

+1  A: 

You get lazy execution until you execute ToList(). At that point, yes, the whole kit and caboodle is pulled down.

If you want more intelligent execution, consider eliminating the ToList() call. Using IQueryables throughout the call chain will allow your repository to retrieve only the five records you need.

Once you have only the five records you need, then you can call ToList().

Robert Harvey
So if I remove the ToList(), and inside the GetPostFeeds function, if i take the top 5 sorted by date, its only that is pulled from the database, or is it still everything?
Shawn Mclean
Yes, that would work. The principle is to call `ToList()` *after* you have done a `.Where()` to get it down to the five records you need. Calling ToList() will force immediate execution, so do the filtering first, *before* calling ToList().
Robert Harvey
You said I should change from IList to IQueryable inside the Service also?
Shawn Mclean
Yes, just pass the `IQueryable` through your service layer `GetPosts()` method to the `GetPostFeeds()` method, and return your `IList` from that.
Robert Harvey
+3  A: 

As long as you're working with IQueryable, query execution can be deferred. The query is executed once you call ToList() or do something else that requires data to be fetched (e.g. iterating over a child collection).

I don't think you need to worry about your DAL too much as I like to keep them fairly lean. You could take advantage of using deferred execution by rewriting your GetPostFeeds method though, e.g.:

//Returns a list of the latest feeds, restricted by the count.
public IList<PostFeed> GetPostFeeds(int latestCount)
{
   var posts = repository.GetPosts();

   // Perform additional filtering here e.g:
   posts = posts.Take(5);

   return posts.ToList();
}
richeym
A: 

Agreed that by leveraging IQueryable you can avoid returning the entire table. If you don't want IQueryable to leak out of your DAL, you might consider moving the take() call into the DAL by expanding the contract so that the DAL exposes a method that accepts a "top n" parameter.

Decker