Reputation: 10512
I have a list of articles sorted by descending rating. If the rating is the same, they are sorted by ascending ID (the IDs are unique):
ID RATING
9 34
3 32
6 32
8 32
12 32
1 25
2 23
I want to query pages of 3 articles, which means the first page will have articles 9, 3 and 6. This is done by querying the top 3 articles form the sorted list.
Now, I want to take the next 3 articles resuming from article 8, using the article ID as marker for where to resume, as opposed to just skipping the first 3 articles. This is because the content of the article table changes very rapidly and a standard pagination approach like this:
var articles =
db.Articles
.OrderByDescending(a => a.Rating).ThenBy(a => a.Id)
.Skip(3)
.Take(3);
would not work reliably because articles can be added or deleted at any time (just assume the rating doesn't change here).
If this was LINQ to Object, I could use SkipWhile
:
var articles =
db.Articles
.OrderByDescending(a => a.Rating).ThenBy(a => a.Id)
.SkipWhile(a => a.Article.Id != 8)
.Take(3);
but SkipWhile
is not implemented in LINQ to SQL (see here).
If I did like this:
var articles =
db.Articles
.Where(a => a.Rating
< db.Articles.Single(aa => aa.Id == 8).Rating)
.OrderByDescending(a => a.Rating)
.Take(3);
I would skip article 12, while if I did something like this:
var articles =
db.Articles
.Where(a => a.Rating
<= db.Articles.Single(aa => aa.Id == 8).Rating)
.OrderByDescending(a => a.Rating)
.Take(3);
I would take articles 3 and 6 twice.
Using LINQ to SQL, what's the best way to resume the pagination from article 8, using the article ID as marker for where to resume?
Upvotes: 0
Views: 562
Reputation: 3621
Can you just do:
var articles =
db.Articles
.OrderByDescending(a => a.Rating).ThenBy(a => a.Id)
.Skip(3)
.Take(3);
Okay, if that won't work, I'd write a function something like this:
static IEnumerable<Article> GetArticles(List<Article> articles, int articlesToRetrieve, int startingID)
{
IEnumerable<Article> results = null;
results = articles.OrderByDescending(a => a.Rating).ThenBy(a => a.ID);
if (startingID > 0)
{
int lastRating = articles.Single(aa => aa.ID == startingID).Rating;
results = results.Where(a => a.Rating < lastRating || (a.Rating == lastRating && a.ID > startingID));
}
if (articlesToRetrieve > 0)
{
results = results.Take(articlesToRetrieve);
}
return results;
}
which I think will do the trick.
Upvotes: 1