Há momentos em que o result-set da base de dados é muito grande, ou seja, é retornado ao cliente uma grande quantidade de registros, o que pode custar muito caro para o mesmo pois recebe todos os registros e exibe apenas os registros que se enquadram na página atual, e limitando ao número de registros por páginas.
A paginação de dados vem justamente para suprir esta necessidade, podendo dar ao usuário uma forma mais simples de navegar pelo result-set e consequentemente, a aplicação ganha muito em performance. O controle GridView já fornece uma arquitetura que permite a paginação automática de registros.
A forma de como habilitar esta opção é idêntica à ordenação de colunas que fizemos anteriormente, ou seja, deve-se clicar na Smart Tag do controle GridView e marcar o CheckBox chamado Enable Paging, como é ilustrado na figura abaixo:
|
Figura 1 – Habilitando a Paginação de Registros. |
Habilitando esta opção, o controle GridView já fará a paginação dos registros automaticamente. Através do código HTML abaixo da página ASPX, vemos como o mesmo ficou configurado:
<asp:GridView ID="GridView1" runat="server" AllowPaging="True" AutoGenerateColumns="False" DataSourceID="SqlDataSource1" PageSize="2"> <Columns> <asp:BoundField DataField="Nome" HeaderText="Nome" /> <asp:BoundField DataField="Email" HeaderText="Email" /> </Columns> </asp:GridView> |
|||
ASPX |
Uma nova propriedade é apresentada: PageSize. Ela é responsável por definir a quantidade de registros que serão apresentados por página.
Utilizando o objeto SqlDataSouce
Como neste objeto temos a propriedade DataSourceMode, onde definimos qual será a forma de recuperar os dados da fonte de dados (Dataset ou DataReader), infelizmente ele não pode ser definido como DataReader, pois para efetuar a paginação o objeto deverá obrigatoriamente implementar a interface ICollection, que é somente o caso do objeto Dataset. Vale lembrar que isso já é um problema conhecido nas versões 1.x do ASP.NET.
Para conseguir a paginação de forma automática temos que definir a propriedade DataSourceMode como Dataset ou omití-la. Mas é importante dizer que nada impedirá você de criar uma paginação e controle customizados para esta situação.
Utilizando o objeto ObjectDataSouce
Ao utilizar este tipo de objeto temos que fazer alguns ajustes para habilitar a paginação no controle GridView. Apesar de existir algumas formas diferentes de se fazer, no exemplo mostrado abaixo a paginação retornará apenas os registros pertinentes a página solicitada pelo usuário. Logo a Stored Procedure responsável por retornar estes registros deve receber dois parâmetros:
- PageNumber – O número da página requisitada pelo usuário.
- PageSize – Quantidade de registros por página.
Abaixo é exibida a Stored Procedure que utiliza subqueries para retornar a quantidade de registros de uma determinada página:
ALTER PROCEDURE dbo.CustomPaging @PageSize As Int, @PageNumber As Int AS DECLARE @COUNTER As Int SET @COUNTER = (SELECT COUNT(*) FROM Usuario) IF @PageNumber = 0 SET @PageNumber = 1 SELECT Nome FROM Usuario WHERE UsuarioID IN (SELECT TOP(@PageSize) UsuarioID FROM Usuario WHERE UsuarioID NOT IN (SELECT TOP(@PageSize * (@PageNumber - 1)) UsuarioID FROM Usuario ORDER BY Nome) ORDER BY Nome) ORDER BY Nome RETURN @COUNTER |
|||
T-SQL |
Agora com o SQL Server 2005 e o SQL Server Express 2005, a cláusula TOP do T-SQL pode ser parametrizada, o que nas versões anteriores só conseguíamos através de uma query dinâmica. A quantidade total de registros (que utilizamos a função COUNT para recuperar) é necessária, pois o objeto ObjectDataSource precisa desse valor para calcular as páginas à serem exibidas ao usuário.
Depois da Stored Procedure pronta vamos analisar a classe de negócios que receberá os parâmetros e executará a Stored Procedure acima. Abaixo o código da classe de negócios:
using System; using System.Data; using System.Data.SqlClient; using System.Configuration; using System.Web; using System.Web.Configuration; using System.Collections.Generic; public class Paging { private int _count = 0; public int TotalUsuarios(){ return this._count; } public List ResgataUsuarios(int pageSize, int pageNumber) { List coll = new List(); SqlConnection conn = new SqlConnection( WebConfigurationManager.ConnectionStrings["ConnString"].ConnectionString); SqlCommand cmd = new SqlCommand("CustomPaging", conn); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("@PageSize", pageSize); cmd.Parameters.AddWithValue("@PageNumber", pageNumber); cmd.Parameters.AddWithValue("@RETURN_VALUE", 0).Direction = ParameterDirection.ReturnValue; SqlDataReader dr = null; try { conn.Open(); dr = cmd.ExecuteReader(CommandBehavior.CloseConnection); while (dr.Read()) { Usuario u = new Usuario(); u.Nome = dr.GetString(0); coll.Add(u); } } finally { if (dr != null) dr.Close(); this._count = Convert.ToInt32(cmd.Parameters["@RETURN_VALUE"].Value); } return coll; } } |
|||
C# | VB.NET |
Analisando o código acima, temos um membro privado na classe Paging, que é responsável por armazenar a quantidade total de registros da base de dados (ou da condição da cláusula SQL). O método ResgataUsuarios que recebe os parâmetros pageSize e o pageNumber, os quais já descrevemos acima suas utilidades, e através dele os mesmos são anexados à coleção de parâmetros do objeto SqlCommand que executa a Stored Procedure.
Através de um objeto SqlDataReader percorremos os registros da base de dados e populamos o objeto Usuario que posteriormente é adicionado à uma coleção genérica deste mesmo tipo.
Já o método TotalUsuarios retorna o valor contido dentro do membro privado denominado _count, o qual representa a quantidade total de registros da base de dados (ou da condição da cláusula SQL). Como já foi falado, o objeto ObjectDataSource ou qualquer outro tipo de paginação requer este valor para calcular e exibir a quantidade de páginas disponíveis ao usuário. Recuperamos este valor total através de um parâmetro do tipo RETURN_VALUE, que a Stored Procedure retorna para a aplicação.
Através do código HTML abaixo da página ASPX, vemos como configurar o objeto ObjectDataSource e o controle GridView corretamente:
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" EnablePaging="True" SelectCountMethod="TotalUsuarios" StartRowIndexParameterName="pageNumber" MaximumRowsParameterName="pageSize" SelectMethod="ResgataUsuarios" TypeName="Paging"> </asp:ObjectDataSource> <asp:GridView ID="GridView1" runat="server" AllowPaging="True" AutoGenerateColumns="False" DataSourceID="ObjectDataSource1" PageSize="2"> <Columns> <asp:BoundField DataField="Nome" HeaderText="Nome" /> </Columns> </asp:GridView> |
|||
ASPX |
Analisando o código HTML da página ASPX acima, vemos duas propriedades que já são de nosso conhecimento: a SelectMethod e TypeName, que foram descritas na seção sobre Tipos de DataSource. Abaixo são listadas as propriedades do objeto ObjectDataSource que ainda não analisamos:
-
EnablePaging – É necessário definir para True quando queremos habilitar a paginação de registros no objeto ObjectDataSource.
-
SelectCountMethod – Definimos nesta propriedade o nome do método da classe de negócios que é responsável por retornar a quantidade total de registros.
-
StartRowIndexParameterName – Baseando-se na classe de negócios que criamos acima, esta propriedade é definida com o nome do parâmetro (pageNumber) responsável pela página que o usuário requisitou.
-
MaximumRowsParameterName – Baseando-se na classe de negócios que criamos acima, esta propriedade é definida com o nome do parâmetro (pageSize) responsável pela quantidade de registros exibidos por página.
Já na configuração do controle GridView não se tem muito à fazer: temos que definir a fonte de dados a ser utilizada; habilitar a paginação através da propriedade AllowPaging e, finalmente, através da propriedade PageSize definir a quantidade de registros que serão exibidos por página. Realizados esses ajustes, o GridView já está pronto para realizar a paginação de registros sem a necessidade de definirmos os valores aos parâmetros, pois o controle GridView em conjunto com o objeto ObjectDataSource fará isso de forma transparente.
A imagem abaixo exibe o controle GridView já em funcionamento utilizando o objeto ObjectDataSource como fonte de dados:
|
Figura 2 – GridView em funcionamento. |