简体   繁体   English

LINQ,Skip和Take订购

[英]LINQ, Skip and Take ordering

I was doing some testing with Take and Skip and I found that: 我正在使用Take和Skip进行一些测试,我发现:

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). GetObjects()返回由NHibernate生成的IQueryable(3.3.3GA,使用SQL Server 2008 R2 DB)。
skipTake and takeSkip contain the same exact sequence of 10 objects. skipTake和takeSkip包含10个对象的完全相同的序列。
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. skipTake包含与上例相同的序列,而takeSkip包含仅5个对象的不同序列。

Do Take and Skip calls get reordered when they are applied on a IQueryable? 将Take和Skip调用应用于IQueryable时会重新排序吗?
I would love to get some insight on this. 我很乐意对此有所了解。

Thanks in advance. 提前致谢。

It looks like this is due to a bug in particular versions of nhibernate: 看起来这是由于特定版本的nhibernate中的一个错误:

http://sourceforge.net/p/nhibernate/news/2013/03/nhiberate-333ga-released/ 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.CR1之前的版本中,LINQ Take()方法的处理存在缺陷 - 无论在查询的哪个位置放置Take(),它总是被应用,就像它被放置在最后一样。 3.3.3 fixes this, so that Take() now correctly follows the .Net semantics. 3.3.3修复此问题,以便Take()现在正确遵循.Net语义。 That is, in 3.3.3, the following queries might now give different results: 也就是说,在3.3.3中,以下查询现在可能会给出不同的结果:

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. 从3.3.3开始,第一个查询将生成一个子查询,以便在where子句之前正确应用行限制。

Do Take and Skip calls get reordered when they are applied on a IQueryable? 将Take和Skip调用应用于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. skipTake是跳过IQueriable的前5个元素并取下10个元素的结果。因此,例如在1到20的有序数字列表中,skipTake将是子列表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 (!). takeSkip是获取IQueriable的前10个元素然后跳过子列表的前5个元素(!)的结果。 So using the list from the previous example, takeSkip would be the sublist 6 --> 10. 因此,使用上一个示例中的列表,takeSkip将是子列表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. 对于观察的第一部分(skipTake和takeSkip包含相同的10个元素),这应该被视为NHibernate实现中的错误行为(或者甚至可能是错误)。

Firstly I find that @ https://stackoverflow.com/users/2617732/rdans answer is irrelevant to your specific example since you do not apply a where clause after the Take . 首先,我发现@ https://stackoverflow.com/users/2617732/rdans答案与您的具体示例无关,因为您没有在Take之后应用where子句。

That said, in example A both skipTake and takeSkip should generate the same SQL where it it would select the first 10 rows after the 5th row, (for SQL server for example that would be with ROW_NUMBER OVER(...) ). 也就是说,在示例A中, skipTaketakeSkip应该生成相同的SQL,它将选择第5行之后的前10行(对于SQL服务器,例如将使用ROW_NUMBER OVER(...) )。

It seems to me that in example B you are trying to perform the Take and Skip not on an IQuerable but on a System.Collections.Generic.List<> (which naturally is not NHibernate territory). 在我看来,在示例B中,您尝试不在IQuerable上执行TakeSkip ,而是在System.Collections.Generic.List<> (当然不是NHibernate区域)上执行。

In this case objects has N elements. 在这种情况下, objects具有N个元素。

skipTake will first Skip 10 elements and from the resulting enumeration (which enumerates over N-10 elements) then Take the first 5 elements. skipTake将首先Skip 10个元素,然后从生成的枚举(枚举N-10个元素)中Take前5个元素。

Given then the results are already ordered the result of skipTake s ToList should be the same with the example A. 在给定结果已经排序的情况下, skipTakeToList的结果应该与示例A相同。

takeSkip on the other hand first Take s 10 elements and from the resulting enumeration (which enumerates over 10 elements) Skip s the first 5. 另一方面, takeSkip首先Take 10个元素并从生成的枚举(枚举超过10个元素) Skip前5 元素。

So, that's that 那就是那个

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM