LINQ,Skip和Take订购

时间:2015-05-20 08:36:53

标签: c# linq nhibernate

我正在使用Take和Skip进行一些测试,我发现:

sudo a2enmod access_compat

GetObjects()返回由NHibernate生成的IQueryable(3.3.3GA,使用SQL Server 2008 R2 DB)。
skipTake和takeSkip包含10个对象的完全相同的序列 但如果我写

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();

skipTake包含与上例相同的序列,而takeSkip包含仅5个对象的不同序列。

当Take和Skip调用应用于IQueryable时会重新排序吗? 我很乐意对此有所了解。

提前致谢。

3 个答案:

答案 0 :(得分:2)

看起来这是由于特定版本的nhibernate中的错误:

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

  

注意:在3.3.3.CR1之前的版本中,处理LINQ Take()方法   有缺陷 - 无论查询在哪里Take()被放置了   总是应用,好像它已被放置在最后。 3.3.3解决了这个问题,   所以Take()现在正确地遵循.Net语义。也就是说,在   3.3.3,以下查询现在可能会给出不同的结果:

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

从3.3.3开始,第一个查询将正确生成子查询   在where子句之前应用行限制。

答案 1 :(得分:0)

  

当Take和Skip调用应用于a时,会重新排序   IQueryable的?我很乐意对此有所了解。

我认为这个问题的答案应该这样制定:

skipTake 是跳过IQueriable的前5个元素并取下一个10的结果。因此,例如在1到20的有序数字列表中,skipTake将是子列表6 - &GT; 15。

takeSkip 是获取IQueriable的前10个元素然后跳过子列表的前5个元素(!)的结果。因此,使用前一个示例中的列表,takeSkip将是子列表6 - &gt; 10。

对于观察的第一部分(skipTake和takeSkip包含相同的10个元素),这应该被视为NHibernate实现中的错误行为(或者甚至可能是错误)。

答案 2 :(得分:0)

首先,我发现@ https://stackoverflow.com/users/2617732/rdans答案与您的具体示例无关,因为您未在Take之后应用where子句。

也就是说,在示例A中,skipTaketakeSkip应该生成相同的SQL,它将选择第5行之后的前10行(对于SQL服务器,例如,它将与ROW_NUMBER OVER(...))。

在我看来,在示例B中,您尝试执行TakeSkip不是IQuerable而是System.Collections.Generic.List<>(当然不是NHibernate)境)。

在这种情况下,objects有N个元素。

skipTake将首先Skip 10个元素,并从最终的枚举(枚举N-10个元素)然后Take前5个元素。

鉴于此后结果已经排序,skipTake s ToList的结果应与示例A相同。

另一方面,

takeSkip首先是Take个10个元素,并且从结果枚举(其中列出 10 元素)Skip开始是前5个元素。

那就是那个