如何:返回或跳过序列中的元素 (LINQ to SQL)

更新:November 2007

使用 Take<TSource> 运算符可返回序列中给定数目的元素,然后跳过其余元素。

使用 Skip<TSource> 运算符可跳过序列中给定数目的元素,然后返回其余元素。

说明:

Take<TSource>Skip<TSource> 用在针对 SQL Server 2000 的查询中时存在一定的限制。有关更多信息,请参见疑难解答 (LINQ to SQL) 中的“SQL Server 2000 中的 Skip 和 Take 异常”项。

LINQ to SQL 通过使用带有 SQL NOT EXISTS 子句的子查询来转换 Skip<TSource>。这种转换存在以下局限性:

  • 参数必须为集合。不支持多重集,即便为有序多重集也不例外。

  • 生成的查询可能要比为应用了 Skip<TSource> 的基查询生成的查询复杂得多。这种复杂性可能会导致性能降低,甚至发生超时。

示例

下面的示例使用 Take 选择前五个受雇的 Employees。请注意,此集合首先按 HireDate 排序。

Dim firstHiredQuery = _
    From emp In db.Employees _
    Select emp _
    Order By emp.HireDate _
    Take 5

For Each empObj As Employee In firstHiredQuery
    Console.WriteLine("{0}, {1}", empObj.EmployeeID, _
        empObj.HireDate)
Next
IQueryable<Employee> firstHiredQuery =
    (from emp in db.Employees
    orderby emp.HireDate
    select emp)
    .Take(5);

foreach (Employee empObj in firstHiredQuery)
{
    Console.WriteLine("{0}, {1}", empObj.EmployeeID,
        empObj.HireDate);
}

下面的示例使用 Skip<TSource> 选择 10 种最贵的 Products 以外的所有产品。

Dim lessExpensiveQuery = _
    From prod In db.Products _
    Select prod _
    Order By prod.UnitPrice Descending _
    Skip 10

For Each prodObj As Product In lessExpensiveQuery
    Console.WriteLine(prodObj.ProductName)
Next
IQueryable<Product> lessExpensiveQuery =
    (from prod in db.Products
    orderby prod.UnitPrice descending
    select prod)
    .Skip(10);

foreach (Product prodObj in lessExpensiveQuery)
{
    Console.WriteLine(prodObj.ProductName);
}

下面的示例结合使用 Skip<TSource>Take<TSource> 方法来跳过前 50 条记录,然后返回下 10 条记录。

Dim custQuery2 = _
    From cust In db.Customers _
    Order By (cust.ContactName) _
    Select cust _
    Skip 50 _
    Take 10

For Each custRecord As Customer In custQuery2
    Console.WriteLine(custRecord.ContactName)
Next
var custQuery2 =
    (from cust in db.Customers
    orderby cust.ContactName
    select cust)
    .Skip(50).Take(10);

foreach (var custRecord in custQuery2)
{
    Console.WriteLine(custRecord.ContactName);
}

Take<TSource>Skip<TSource> 运算仅对有序集而言是定义完善的。未定义针对无序集或多重集的语义。

由于 SQL 中的排序存在限制,因此 LINQ to SQL 会设法将 Take<TSource>Skip<TSource> 运算符的参数的排序操作移到相应运算符的结果中进行。

说明:

对于 SQL Server 2000 和 SQL Server 2005,转换是不同的。如果您打算将 Skip<TSource> 与具有任意复杂度的查询一起使用,请使用 SQL Server 2005。

请考虑下面这个针对 SQL Server 2000 的 LINQ to SQL 查询:

Dim custQuery3 = _
    From custs In db.Customers _
    Where custs.City = "London" _
    Select custs _
    Order By custs.CustomerID _
    Skip 1 _
    Take 1

For Each custObj In custQuery3
    Console.WriteLine(custObj.CustomerID)
Next
IQueryable<Customer> custQuery3 =
    (from custs in db.Customers
     where custs.City == "London"
     orderby custs.CustomerID
     select custs)
    .Skip(1).Take(1);

foreach (var custObj in custQuery3)
{
    Console.WriteLine(custObj.CustomerID);
}

LINQ to SQL 将排序操作移到 SQL 代码的结尾进行,如下所示:

SELECT TOP 1 [t0].[CustomerID], [t0].[CompanyName],
FROM [Customers] AS [t0]
WHERE (NOT (EXISTS(
    SELECT NULL AS [EMPTY]
    FROM (
        SELECT TOP 1 [t1].[CustomerID]
        FROM [Customers] AS [t1]
        WHERE [t1].[City] = @p0
        ORDER BY [t1].[CustomerID]
        ) AS [t2]
    WHERE [t0].[CustomerID] = [t2].[CustomerID]
    ))) AND ([t0].[City] = @p1)
ORDER BY [t0].[CustomerID]

Take<TSource>Skip<TSource> 链接在一起时,所有指定的排序都必须一致。否则,结果将是不确定的。

对于非负的、基于 SQL 规范的整型常量参数,Take<TSource>Skip<TSource> 都是定义完善的。

请参见

参考

标准查询运算符转换 (LINQ to SQL)

其他资源

查询示例 (LINQ to SQL)