Поделиться через


Как возвращать или пропускать элементы последовательности (LINQ to SQL)

Обновлен: November 2007

Для возвращения заданного числа элементов последовательности и пропуска оставшихся используется оператор Take<TSource>.

Для пропуска заданного числа элементов последовательности и возвращения оставшихся используется оператор Skip<TSource>.

Bb386988.alert_note(ru-ru,VS.90).gifПримечание.

Методы Take<TSource> и Skip<TSource> имеют некоторые ограничения, когда они применяются в запросах SQL Server 2000. Дополнительные сведения см. в подразделе "Исключения методов "Skip" и "Take" в SQL Server 2000" раздела Устранение неполадок (LINQ to SQL).

LINQ to SQL преобразует Skip<TSource> с помощью вложенного запроса с предложением NOT EXISTS SQL. Это преобразование имеет следующие ограничения.

  • Необходимо задать значение аргумента. Не поддерживаются множественные наборы, даже упорядоченные.

  • Созданный запрос может быть сложнее, чем запрос, созданный для основного запроса, к которому применен Skip<TSource>. Это может стать причиной снижения производительности или даже привести к превышению времени ожидания.

Пример

В следующем примере для выбора первых пяти принятых на работу Employees используется метод Take. Обратите внимание, что коллекция сначала сортируется по 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);
}

В следующем примере для выбора всех Products, за исключением 10 самых дорогих, используется метод Skip<TSource>.

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

В следующем примере для пропуска первых 50 и возвращения следующих за ними 10 записей методы Skip<TSource> и Take<TSource> объединяются.

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>в результат оператора.

Bb386988.alert_note(ru-ru,VS.90).gifПримечание.

Преобразование для SQL Server 2000 отличается от преобразования SQL Server 2005. Если планируется применять метод Skip<TSource> в запросах любой сложности, используйте SQL Server 2005.

Рассмотрим следующий запрос LINQ to SQL для SQL Server 2000.

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> друг с другом все указанные операции упорядочения должны быть согласованы. В противном случае результаты не определены.

Методы Take<TSource> и Skip<TSource> правильно определяются для неотрицательных постоянных целочисленных аргументов, соответствующих спецификации SQL.

См. также

Ссылки

Преобразование стандартных операторов запросов (LINQ to SQL)

Другие ресурсы

Примеры запросов (LINQ to SQL)