Postoji i bolje resenje, ovo je primer za LINQ to SQL (PagingDataContext je vezan za AdventureWorks bazu, tabela Contacts):
Code:
public string[] GetPage(int pageIndex, int pageSize)
{
PagingDataContext db = new PagingDataContext();
var prezimena = from p in db.Contacts
orderby p.LastName
select p.LastName;
// izvuci stranicu
prezimena = prezimena.Skip(pageIndex * pageSize).Take(pageSize);
// izvrsi SQL i vrati podatke
return prezimena.ToArray();
}
public string[] GetPage(int pageIndex, int pageSize)
{
PagingDataContext db = new PagingDataContext();
var prezimena = from p in db.Contacts
orderby p.LastName
select p.LastName;
// izvuci stranicu
prezimena = prezimena.Skip(pageIndex * pageSize).Take(pageSize);
// izvrsi SQL i vrati podatke
return prezimena.ToArray();
}
Obratite paznju na Skip<>() i Take<>() ekstenzije, prva kaze preskoci toliko elemenata, druga kaze onda uzmi toliko elemenata. Ocekivao sam relano da LINQ to SQL ucita sve podatke i da onda offline premota kolekciju, medjutim kad se pozove sa pageIndex = 12 i pageSize = 10, LINQ to SQL generise sledeci upit.
Code:
exec sp_executesql N'
SELECT [t1].[LastName]
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [t0].[LastName]) AS [ROW_NUMBER], [t0].[LastName]
FROM [Person].[Contact] AS [t0]
) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1
ORDER BY [t1].[ROW_NUMBER]
',N'@p0 int,@p1 int',@p0=120,@p1=10
exec sp_executesql N'
SELECT [t1].[LastName]
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [t0].[LastName]) AS [ROW_NUMBER], [t0].[LastName]
FROM [Person].[Contact] AS [t0]
) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1
ORDER BY [t1].[ROW_NUMBER]
',N'@p0 int,@p1 int',@p0=120,@p1=10
Ova skripta bukvalno vraca samo 10 redova pocev od 121-og i veoma je brza, execution tree je potpuno linearan, iz 5 operacija i ako je orderby pokriven indeksom skeniranje indeksa i generisanje segmenta sa brojem reda je veoma, veoma brzo. Na kraju je i sam ekterni IO rasterecen jer se salje samo pageSize redova. Iako se podaci izvlace iz nested tabele, nema nikave transofrmacije pa se polja direktno prenose u finalni recordset, a posto je ROW_NUMBER vec napravljen inkrementalno nad zeljenim sortom, finalni rezultat sortiran po ROW_NUMBER je takodje sortiran po istom redosledu
Cak iako ne koristite LINQ to SQL, moze lako da se napravi adapter ili DataReader koristeci sledecu formu SQL-a:
Code:
SELECT <lista polja iz B koja matchuje donju listu polja iz A>
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY <sort lista iz A>) AS ROW_NUMBER, <lista polja iz A>
FROM <source tabela> AS A
) AS B
WHERE B.ROW_NUMBER BETWEEN <donja granica> AND <gornja granica>
ORDER BY B.ROW_NUMBER
SELECT <lista polja iz B koja matchuje donju listu polja iz A>
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY <sort lista iz A>) AS ROW_NUMBER, <lista polja iz A>
FROM <source tabela> AS A
) AS B
WHERE B.ROW_NUMBER BETWEEN <donja granica> AND <gornja granica>
ORDER BY B.ROW_NUMBER
Sloba je za 12 godina promenio antropološki kod srpskog naroda. On je od jednog
naroda koji je bio veseo, pomalo površan, od jednog naroda koji je bio znatiželjan, koji
je voleo da vidi, da putuje, da upozna,
od naroda koji je bio kosmopolitski napravio narod koji je namršten, mrzovoljan,
sumnjicav, zaplašen, narod koji se stalno nešto žali, kome je stalno neko kriv - Z.Đinđić
naroda koji je bio veseo, pomalo površan, od jednog naroda koji je bio znatiželjan, koji
je voleo da vidi, da putuje, da upozna,
od naroda koji je bio kosmopolitski napravio narod koji je namršten, mrzovoljan,
sumnjicav, zaplašen, narod koji se stalno nešto žali, kome je stalno neko kriv - Z.Đinđić