Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LINQ, Skip and Take ordering

I was doing some testing with Take and Skip and I found that:

var objects = (from c in GetObjects() orderby c.Name select c);
var skipTake = objects.Skip(5).Take(10).ToList();
var takeSkip = objects.Take(10).Skip(5).ToList();

GetObjects() returns an IQueryable generated by NHibernate (3.3.3GA, using a SQL Server 2008 R2 DB).
skipTake and takeSkip contain the same exact sequence of 10 objects.
But if I write

var objects = (from c in GetObjects() orderby c.Name select c).ToList();
var skipTake = objects.Skip(5).Take(10).ToList();
var takeSkip = objects.Take(10).Skip(5).ToList();

skipTake contains the same sequence as the above example while takeSkip contains a different sequence of just 5 objects.

Do Take and Skip calls get reordered when they are applied on a IQueryable?
I would love to get some insight on this.

Thanks in advance.

like image 701
Matteo Saporiti Avatar asked May 20 '15 08:05

Matteo Saporiti


2 Answers

It looks like this is due to a bug in particular versions of nhibernate:

http://sourceforge.net/p/nhibernate/news/2013/03/nhiberate-333ga-released/

BEWARE: In versions prior to 3.3.3.CR1, the handling of the LINQ Take() method was flawed - no matter where in the query Take() was placed it was always applied as if it had been placed at the end. 3.3.3 fixes this, so that Take() now correctly follows the .Net semantics. That is, in 3.3.3, the following queries might now give different results:

session.Query<Foo>.OrderBy(...).Take(5).Where(...);
session.Query<Foo>.Where(...).OrderBy(...).Take(5);

Starting with 3.3.3, the first query will generate a subquery to correctly apply the row limit before the where-clause.

like image 134
rdans Avatar answered Nov 10 '22 01:11

rdans


Do Take and Skip calls get reordered when they are applied on a IQueryable? I would love to get some insight on this.

I think the answer to this question should be formulated this way:

skipTake is the result of skipping the first 5 elements of the IQueriable and taking the next 10. So for example in a list of ordered numbers from 1 to 20 skipTake would be the sublist 6 --> 15.

takeSkip is the result of taking the first 10 elements of the IQueriable and then skipping the first 5 elements of the sublist (!). So using the list from the previous example, takeSkip would be the sublist 6 --> 10.

For the first part of your observation (where the skipTake and takeSkip contain the same 10 elements), this should be considered as wrong behaviour (or probably even a bug) in the NHibernate implementation.

like image 32
Ramanagom Avatar answered Nov 09 '22 23:11

Ramanagom