views:

1028

answers:

2

What's the best pattern to get paginated results with LINQ to SQL?

I have the following scenario:

Suppose I want to search items table by description. I can easily do:

public IQueryable<Item> FindItemsByDescription(string description)
{
   return from item in _dc.Items
          where item.Description.Contains(description);
}

Now, what would be the best way to paginate this result set?

  1. Should I perform a count query before doing this to find out the result set size and then limit this query according to what I want? I feel like this is the way to go.
  2. Should I perform the full query, take the count from the array size and return only a paginated subset from this array? I feel like this will be a huge waste of time if the resultset is big enough... Or is LINQ to SQL doing some magic here?

Is there a LINQ to SQL common pattern for performing this operation?

EDIT: I must clarify a one little thing. I am aware of Take and Skip methods. But, before using Take and Skip, how should I get the total count of results that query would retrieve?

+1  A: 

You can use the Take extension method:

public IQueryable<Item> FindItemsByDescription(string description, int resultAmount)
{
   return from item in _dc.Items
          where item.Description.Contains(description).Take(resultAmount);
}

You can take this one step further and use Skip for subsequent "pages":

public IQueryable<Item> FindItemsByDescription(string description, int resultAmount, int page)
{
   return from item in _dc.Items
          where item.Description.Contains(description).Skip(resultAmount * page).Take(resultAmount);
}
BFree
Thanks a lot for the quick answer. I am aware of Take and Skip methods exitence. However, if I really want to paginate I must know what's the total number of results without paginating. So, what's the best way to get that *total number*?
Pablo Santa Cruz
+4  A: 

The pattern for paging is very simple. It involves the use of the Skip() and Take() extension methods as follows:

public IQueryable<Item> FindItemsByDescription(string description, int pageIndex, int pageSize)
{
   return from item in _dc.Items
          where item.Description.
          Contains(description).
          Skip((pageIndex - 1) * pageSize).
          Take(pageSize);
}

UPDATE: To get the total count simply use the Count() method:

int totalCount = from item in _dc.Items
                 where item.Description.
                 Contains(description).Count();

int numberOfPages = (int)(totalCount/pageSize);

Depending on how you are going to the display the records, you can use the numberOfPages to display a navigation bar with "Page X of Y" ... Page 1 of 10, etc..

Jose Basilio
Pablo - I updated my post to include more information on paging. (Salu2)
Jose Basilio
Thanks a lot Basilio. Is this, performance wise, the best way to do it? Do you know how many queries will be performed against SQL server with this approach?
Pablo Santa Cruz
Pablo - The code in the example would perform 2 separate SQL queries. However, this does not have to be the case. You can take the results from the query and put it into a list by using ToList(), then get the Count() from that. So that you end up with only one call to the database.
Jose Basilio
"(int)(totalCount/pageSize)" is wrong. Suppose you have 5 items and the page size is 4? The page count will be 1 instead of 2. You also need to test whether totalCount%pageSize==0 or not and add another unit or not.
Andrei Rinea
@Andrei - Very good observation.
Jose Basilio