Во многих приложениях есть сетки, которые отображают данные из таблицы базы данных на одной странице. Многие из них также позволяют пользователю выбирать количество записей на странице, сортировать по любому столбцу и перемещаться вперед-назад по результатам.
Каким алгоритмом можно реализовать этот шаблон, не вынося всю таблицу на клиент и не фильтруя данные на клиенте. Как вывести на экран только те записи, которые вы хотите показать пользователю?
Упрощает ли LINQ это решение?
На MS SQL Server 2005 и выше, ROW_NUMBER(), кажется, работает:
T-SQL: Пейджинг с ROW_NUMBER()
DECLARE @PageNum AS INT;
DECLARE @PageSize AS INT;
SET @PageNum = 2;
SET @PageSize = 10;
WITH OrdersRN AS
(
SELECT ROW_NUMBER() OVER(ORDER BY OrderDate, OrderID) AS RowNum
,OrderID
,OrderDate
,CustomerID
,EmployeeID
FROM dbo.Orders
)
SELECT *
FROM OrdersRN
WHERE RowNum BETWEEN (@PageNum - 1) * @PageSize + 1
AND @PageNum * @PageSize
ORDER BY OrderDate
,OrderID;
I' d рекомендуют или использующий LINQ или пытаются скопировать то, что он делает. I' ve получил приложение, где я использую LINQ, Берут и методы Пропуска, чтобы восстановить пронумерованные страницы данные. Кодекс выглядит примерно так:
MyDataContext db = new MyDataContext();
var results = db.Products
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize);
Управление Профилировщиком SQL-сервера показывает, что LINQ преобразовывает этот вопрос в SQL, подобный:
SELECT [ProductId], [Name], [Cost], and so on...
FROM (
SELECT [ProductId], [Name], [Cost], [ROW_NUMBER]
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [Name]) AS [ROW_NUMBER],
[ProductId], [Name], [Cost]
FROM [Products]
)
WHERE [ROW_NUMBER] BETWEEN 10 AND 20
)
ORDER BY [ROW_NUMBER]
Без обиняков:
Есть по существу два способа сделать нумерацию страниц в базе данных (I' m принимающий you' ре используя SQL-сервер):
Другие объяснили, как 'ROW_NUMBER () ПО ()' оценивающий функцию может использоваться, чтобы выполнить страницы. It' s стоящий упоминания, что SQL-сервер 2012 наконец включал поддержку стандарта SQL 'ПОГАШЕНИЕ.. ПРИНЕСИТЕ' пункт:
SELECT first_name, last_name, score
FROM players
ORDER BY score DESC
OFFSET 40 ROWS FETCH NEXT 10 ROWS ONLY
Если you' ре используя SQL-сервер, 2012 и назад-совместимость не проблема, Вы должны, вероятно, предпочесть этот пункт, поскольку это будет выполнено более оптимально SQL-сервером в угловых случаях.
Есть совершенно различное, намного быстрее, но менее известный способ выполнить оповещение в SQL. Это часто называют " ищите method" как описано в это сообщение в блоге здесь.
SELECT TOP 10 first_name, last_name, score
FROM players
WHERE (score < @previousScore)
OR (score = @previousScore AND player_id < @previousPlayerId)
ORDER BY score DESC, player_id DESC
'@previousScore' и ценности '@previousPlayerId' - соответствующие значения последнего отчета от предыдущей страницы. Это позволяет Вам приносить " next" страница. Если 'ЗАКАЗ' направлением - 'ASC', просто используйте '>'; вместо этого.
С вышеупомянутым методом Вы не можете немедленно подскочить до страницы 4 не сначала принеся предыдущие 40 отчетов. Но часто, Вы не хотите подскакивать это далеко так или иначе. Вместо этого Вы получаете намного более быстрый вопрос, который мог бы быть в состоянии принести данные в постоянное время, в зависимости от Вашей индексации. Плюс, Ваши страницы остаются " stable" неважно, если основные данные изменяются (например, на странице 1, в то время как you' ре на странице 4).
Это - лучший способ осуществить оповещение когда ленивая погрузка большего количества данных в веб-приложениях, например.
Отметьте, " ищите method" также назван [оповещением клавиатуры] (https://stackoverflow.com/a/3215973/521799).
LINQ, объединенный с выражениями лямбды и анонимными классами в.Net 3.5 hugely, упрощает этот вид вещи.
Сомнение базы данных:
var customers = from c in db.customers
join p in db.purchases on c.CustomerID equals p.CustomerID
where p.purchases > 5
select c;
Количество отчетов за страницу:
customers = customers.Skip(pageNum * pageSize).Take(pageSize);
Сортировка любой колонкой:
customers = customers.OrderBy(c => c.LastName);
Получение только отобранных областей от сервера:
var customers = from c in db.customers
join p in db.purchases on c.CustomerID equals p.CustomerID
where p.purchases > 5
select new
{
CustomerID = c.CustomerID,
FirstName = c.FirstName,
LastName = c.LastName
};
Это создает статически напечатанный анонимный класс, в котором Вы можете получить доступ к его свойствам:
var firstCustomer = customer.First();
int id = firstCustomer.CustomerID;
Результаты вопросов лениво загружены по умолчанию, таким образом, Вы - not' t говорящий с базой данных, пока Вам на самом деле не нужны данные. LINQ в.Net также значительно упрощает обновления, держа datacontext любых изменений, которые Вы внесли, и только обновление областей, которые Вы изменяете.
Решение Oracle:
select * from (
select a.*, rownum rnum from (
YOUR_QUERY_GOES_HERE -- including the order by
) a
where rownum <= MAX_ROW
) where rnum >= MIN_ROW
Есть несколько решений, которые я использую с MS SQL 2005.
Один из них - ROW_NUMBER (). Но, лично, я don' t как ROW_NUMBER (), потому что это doesn' t работа для больших результатов (DB, которая я продолжаю работать, действительно большая - данные на более чем 1 TB бегущие тысячи вопросов во втором - Вы знаете - большой сайт социальной сети).
Вот мое любимое решение.
Я буду использовать вид псевдо кодекса T-SQL.
Let' s находят 2-ю страницу пользователей сортированной именем, фамилией, где у каждой страницы есть 10 отчетов.
@page = 2 -- input parameter
@size = 10 -- can be optional input parameter
if @page < 1 then begin
@page = 1 -- check page number
end
@start = (@page-1) * @size + 1 -- @page starts at record no @start
-- find the beginning of page @page
SELECT TOP (@start)
@forename = forename,
@surname = surname
@id = id
FROM
users
ORDER BY
forename,
surname,
id -- to keep correct order in case of have two John Smith.
-- select @size records starting from @start
SELECT TOP (@size)
id,
forename,
surname
FROM
users
WHERE
(forename = @forename and surname = @surname and id >= @id) -- the same name and surname, but bigger id
OR (forename = @forename and surname > @surname) -- the same name, but bigger surname, id doesn't matter
OR (forename > @forename) -- bigger forename, the rest doesn't matter
ORDER BY
forename,
surname,
id
На самом деле, LINQ имеет методы Skip и Take, которые можно комбинировать, чтобы выбрать, какие записи будут извлечены.
Проверьте их.
Для БД: Pagination In SQL Server 2005
Есть дискуссия об этом Здесь
Техника получает номер страницы 100,000 от 150 000 баз данных линии в 78 мс
Используя знание оптимизатора и НАБОР ROWCOUNT, первый EmployeeID на странице, которую требуют, сохранен в местной переменной для отправной точки. Затем, ROWCOUNT НАБОРА к максимальному количеству отчетов, которое требуют в @maximumRows. Это позволяет оповещению набор результата намного более эффективным способом. Используя этот метод также использует в своих интересах существующие ранее индексы на столе, поскольку это идет непосредственно в базисную таблицу а не в в местном масштабе составленную таблицу.
Я боюсь, что не в состоянии судить, лучше ли это, чем ток принял ответ.