Custom Paging com a DataGrid
no ASP.NET
Os métodos
de paginação tradicionais sempre foram problemáticos.
Em geral eles trazem todos os dados do servidor de banco para o servidor
Web a cada página exibida, gerando um grande tráfego de
informações.
Isso acontecia no
ASP 3.0, onde o algorítimo de paginação que era amplamente
divulgado causava esse problema. Para o ASP eu escrevi um artigo sobre
a paginação em ... explicando como resolver o problema.
Mas isso também
acontece no ASP.NET . A metodologia padrão de realizar paginação
através da Grid causa esse mesmo excesso de tráfego entre
o servidor de dados e o servidor Web, gerando problemas de performance
e escalabilidade especialmente quando o conjunto de dados é realmente
grande.
Para resolver isso
a DataGrid nos fornece o recurso de Custom Paging. Através deste
recurso podemos criar uma paginação personalizada que nos
permitirá ir ao banco buscar apenas o conjunto de dados que será
exibido em uma determinada página, otimizando desta forma a transmissão
de dados entre o servidor de dados e o servidor Web.
Estão sendo
divulgadas duas formas de realizar o custom paging. A primeira, mais simples,
depende da existência de uma numeração sequencial
nos registros. E na maioria das vezes nem identity é, pois o identity
pode ter falhas de sequencia em casos de uma deleção, por
exemplo. Para que o algorítimo mais simples funcione precisa ser
uma numeração realmente sequencial nos registros. Como ter
essa numeração nem sempre é possível, não
irei demonstrar este algorítmo, mas vocês podem observa-lo
em ....
A outra forma de paginação
pode ser realizada apenas com a chave primária da tabela. A recuperação
de dados deverá ser feita de forma ordenada pela chave primária.
Na verdade não precisa ser chave primária, pode ser outro
campo qualquer, mas se houver conteúdo duplicado isso poderá
causar problemas para o algorítmo.
Mas existe um porém
nisso tudo : Apenas o algorítmo básico de custom paging,
onde se tem uma numeração sequencial dos registros, permite
uma navegação através dos números de página,
na qual o usuário possa pular diretamente para uma pagina específica.
O algorítimo que demonstrarei não permite isso. Poderia
dizer que é praticamente uma impossibilidade. Na verdade daria
para tratar um pouco mais o SQL para que isso fosse possível mas
certamente as instruções SQL ficariam tão pesadas
que não valeria a pena.
Então vamos
a montagem da aplicação. Farei o exemplo com a tabela products
no NorthWind, paginando de 5 em 5 registros. Para isso precisaremos, além
do objeto de conexão com o banco, de 3 Commands : cmdTotal, para
recuperar o total de registros existentes, cmdNext, cuja query irá
buscar a próxima página a ser exibida e cmdPrevious, cuja
Query irá buscar a página anterior a ser exibida.
Vejam as querys dos
3 :
CmdTotal :
SELECT COUNT(*) AS total FROM Products
CmdNext :
SELECT TOP 5 Products.* FROM Products WHERE (ProductID > ?)
Observe como o ProductID funciona como critério para a obtenção
dos dados
CmdPrevious :
SELECT *
FROM (SELECT TOP 5 Products.*
FROM Products
WHERE productid < ?
ORDER BY productid DESC) a
ORDER BY ProductID
Mais uma vez o productID
funciona como critério para a obtenção dos dados,
mas essa query é bem mais complexa.. Isso porque para recuperar
os 5 registros anteriores ao parâmetro (?) é necessário
usar uma ordem decrescente (order by ... DESC). Mas não podemos
exibir os dados em ordem decrescente, por isso foi ncessário transformar
isso em subquery fazendo por fora um novo order by.
Como esta query é
bem mais complexa, o command não consegue identificar automaticamente
o parâmetro (?). Precisamos então criar esse parâmetro
manualmente, entrando na coleção Parameters do command e
adicionando um parâmetro com o nome de ProductId.
A configuração
da Grid é bem simples. Podemos configurar a paginação
normalmente, com o detalhe de que além de configura-la precisamos
marcar a checkbox "Allow Custom Paging", que fará com
que a grid não processe a paginação, mas deixe que
nós forneçamos os dados a serem exibidos.
A montagem das colunas
também é simples. O fato da grid não estar vinculada
em design não nos impede de montar as colunas. Basta selecionar
a bound column e joga-la para a caixa da direita quantas vezes desejarmos.
Precisaremos lembrar dos nomes dos campos para configura-los (productid,
productname, unitprice).
Vamos, enfim, iniciar
a codificação. Precisaremos de uma variável declarada
no nível da página. Esta variável irá guardar
o índice (productID) que deve ser usado nas instruções
SQL para determinar os dados a serem exibidos. Fica da seguinte forma
:
Dim StartIndex
as Int16
Feito isso, precisaremos
codificar 3 subs :
Page_Load :
Será responsável por configurar a carga do primeiro conjunto
de dados.
VincularDados : Será responsável por usar a variável
startIndex mais um parâmetro recebido para realizar a carga de
dados.
DG_PageIndexChanged : Será responsável por configurar
a carga da página seguinte
Desta forma teremos apenas uma sub que irá buscar os dados para
preencher as páginas : VincularDados. As outras duas irão
configurar as variáveis e parâmetros para que a VincularDados
faça o trabalho corretamente.
Vejamos como ficará
o Page_Load :
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.Load
'Put user code to initialize the page here
If Not Page.IsPostBack Then
CN.Open()
DG.VirtualItemCount = cmdTotal.ExecuteScalar
StartIndex = 0
CN.Close()
VincularGrid(1)
End If
End Sub
Utilizando o Custom
paging é sempre necessário configurar a propriedade VirtualItemCount
com o total de registros que serão exibidos para que a grid acerte
a exibição dos links de paginação. Além
disso, como irá fazer a primeira recuperação, o page_load
configurar o StartIndex para 0 (vai pegar registros com productid superior
a 0) e chama a sub VincularGrid transmitindo o valor 1, que indica que
deve ser feita uma movimentação para a próxima página.
Tudo isso isolado pelo teste de PostBack, pois deve ocorrer apenas uma
vez, a primeira vez que a página é chamada.
Vamos agora ver o
PageIndexChanged :
Private Sub DG_PageIndexChanged(ByVal source As Object, ByVal e As _
System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles DG.PageIndexChanged
Dim tarefa As Int16
If DG.CurrentPageIndex < e.NewPageIndex Then
StartIndex = DG.DataKeys(4)
tarefa = 1
Else
StartIndex = DG.DataKeys(0)
tarefa = 2
End If
DG.CurrentPageIndex = e.NewPageIndex
VincularGrid(tarefa)
End Sub
O PageIndexChanged
identifica se a movimentação que está sendo feita
é para a próxima página ou para a página anterior.
Se for para a próxima página o StartIndex recebe a chave
(ProductID) do último registro exibido, para que na query seguinte
sejam buscados mais 5 registros maiores que esta chave. Mas se a movimentação
foi para a página anterior o StartIndex recebe a chave do primeiro
registro exibido, para que a query busque os 5 registros anteriores a
esse código.
Feita a configuração,
a Grid é avisada da mudança de página e chama-se
o vincularGrid. É transmitido 1 para indicar a movimentação
para a próxima página ou 2 para indicar a movimentação
para a página anterior.
Vamos então
conhecer o código do VincularGrid :
Private Sub VincularGrid(ByVal Direcao As Int16)
CN.Open()
If Direcao = 1 Then
cmdNext.Parameters("ProductID").Value = StartIndex
DG.DataSource = cmdNext.ExecuteReader()
Else
cmdPrevious.Parameters("ProductID").Value = StartIndex
DG.DataSource = cmdPrevious.ExecuteReader
End If
DG.DataKeyField = "ProductId"
DG.DataBind()
CN.Close()
End Sub
O Command que será
executado muda conforme o parâmetro recebido. 1 indica para executar
o cmdnext, caso seja outro valor o command executado será o cmdPrevious.
Com isso e a diferença na instrução SQL dos dois
conseguimos a movimentação para a próxima página
ou para a página anterior.
Observem que antes
de fazer o DataBind configuramos o DataKeyField. Essa configuração
gerará a facilidade para o PageIndexChanged recuperar o valor do
ProductID quando precisar (observe que no código do PageIndexChanged
utilizamos a coleção DataKeys).
Com esse exemplo conseguimos
otimizar a paginação na grid, criando uma paginação
real, ao invés das falsas paginações que normalmente
são divulgadas.
Dennes Torres
MCSD,MCSE,MCDBA
|