1

I want to use linq to show a sequence in pages, where operators can request to show the previous page or the next page. Each page has a constant page size.

Several questions on stackoverflow handle how to do this, a.o. Paging with LINQ for objects

The solutions suggest using Skip and Take. This works fine as long as the sequence does not change while viewing it. But if items are inserted or removed while viewing a page, you'll miss items.

Example: page size = 10 items. I am viewing page 8 (zero based) containing items 80 to 89. Obviously if I press pageup I want to see items 70 to 79. However, if someone inserted 5 items somewhere near item 25 (so way out of the page I am viewing), I will miss some items.

The cause of this is because the software thinks that page 8 is being viewed, while because of the insertions I am in fact viewing page 8.5.

So instead of using Skip(pagenumber * pagesize) I should use a function that returns the elements after a given element, or before a given item in the sequence. Normally SkipWhile(...) would be enough:

private static IEnumerable<T> ItemsAfter(this IEnumerable<T> source,
    Func<TSource, bool> predicate, int pageSize)
{
   return source.Orderby(...)
                .SkipWhile(predicate)
                .Take(pageSize)
}

However SkipWhile is not recognized by LINQ to entities. So is there an alternative?

Addition: What I want is: given an element from a sorted sequence, give me the next 10 elements (or the previous 10) I think the solution is somewhere near SQL Fetch Next and Fetch Prior, but haven't found a good explanation for it yet.

Community
  • 1
  • 1
Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116
  • 1
    I do think it is a strange prerequisite. With your method, you could have a page 0, a page -1, a page -2 and so on (you are in page 2, someone inserts enough rows in page 1, and now your pages go to negative numbers) – xanatos Feb 24 '16 at 12:18
  • So your not talking about a page number, you are talking about the previous 10 elements to show, or the next 10 elements to show. – Harald Coppoolse Feb 24 '16 at 12:44

1 Answers1

0

It is very hard to come up with a replacement for SkipWhile because EF does not support any of the numbering functions either. Therefore everything based on relative order is hard.

Here, you probably can make use of the following query form:

   return source
            .Where(x => x.PositioningKey > lastSeenValue)
            .Orderby(x => x.PositioningKey)
            .Take(pageSize)
usr
  • 168,620
  • 35
  • 240
  • 369
  • Actually, this is what I want: give me the pageSize number of items from a sorted sequence starting at item lastSeenValue. However, If I have an ordered sequence, I can find the last seen value, for instance by Id, but how to find which values com after it? – Harald Coppoolse Feb 24 '16 at 12:56
  • Why doesn't `PositioningKey > lastSeenValue` work for that? Not sure I understand. Concretely, `Id > lastSeenId`. – usr Feb 24 '16 at 13:05
  • Call me stupid, but I don't understand what you mean by PositioningKey and lastSeenValue. They are not linq members. – Harald Coppoolse Feb 24 '16 at 13:30
  • You want to sort by something, right? You want to show sorted by order number or whatever. So say "where x.OrderNumber > lastOrderNumberThatWasOnThePreviousPage". You need to track that value and to me it seemed you are already tracking that and wanting to use that for the SkipWhile call. – usr Feb 24 '16 at 13:44
  • Ok, I understand what you mean. Suppose I have a sequence of Persons, sorted by surname, then by primary key. There are 40 John Doe in the sequence. I am currently displaying John Doe 5 to John Doe 15. Now I want to show the first 10 items after John Doe 15. My last found item had Surname John Doe. I know the primary key of my last found John Doe, so I can Find it again. but which Person comes after my last found John Doe? – Harald Coppoolse Feb 24 '16 at 14:27
  • You need to define a total sort order e.g. `Surname, ID`. You can then do `where x.Surname > sn || x.Surname == sn && x.ID > id`. This is ugly but works. – usr Feb 24 '16 at 14:31
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/104436/discussion-between-haralddutch-and-usr). – Harald Coppoolse Feb 24 '16 at 14:44