Paginando dados com DataList


O grande problema, é que retornamos ao cliente registros indispensáveis para página corrente, o que de certa forma, causa um grande tráfego na rede para no final ser desconsiderado. Sendo assim, retornar todos os registros, e armazenar em uma variável de sessão, também é muito custoso, talvez quando o acesso é mínimo, não se perceba, mas quando a quantidade de usuários requisitando a mesma informação, isso poderá ocasionar sérios problemas de performance.

Tendo este cenário e/ou problema, a solução seria retornarmos da base de dados somente os registros correspondentes a página qual o usuário requerer. Além de diminuir o tráfego de dados na rede, isso nos proporcionará um grande ganho de performance. O artigo mostrará como retornar somente os registros da base de dados qual se enquadram com a página que o usuário requerer. Isso será feito através de uma Stored Procedure, utilizando a tabela Customers da base de dados Northwind como exemplo. Através de um SqlDataReader, recuperamos o result set retornado pela Stored Procedure e populamos o controle DataList.

O primeiro passo e construirmos a Stored Procedure para nos retornar os registros que necessitamos. Com isso, precisamos informar a ela a pagina requerida pelo Usuário, a quantidade de registros à ser exibido por página e também criarmos um parâmetro de OUTPUT para sabermos a quantidade total de registros, que é necessário para efetuar os cálculos no cliente, para que seja possível manipular corretamente a navegação entre as páginas. Abaixo a Stored Procedure responsável por devolver apenas os registros que necessitamos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 
CREATE PROCEDURE ResgatarClientes
 
    @QtdePagina As Int,
    @PagAtual As Int,
    @TotalClientes As Int OUTPUT
 
    AS
 
    DECLARE @ContactName As Varchar(50)
    DECLARE @City As Varchar(50)
    DECLARE @QtdeInicial As Int
    DECLARE @Contador As Int
 
    SET @QtdeInicial = 0
    SET @Contador = 0
 
    SET NOCOUNT ON
 
    CREATE TABLE #ClientesTemp
    (
        ContactName Varchar(50)
        City Varchar(50)
    )
 
    DECLARE curPaginacaoClientes CURSOR FAST_FORWARD FOR
        SELECT ContactName, City FROM Customers ORDER BY ContactNameASC
 
    OPEN curPaginacaoClientes
    FETCH NEXT FROM curPaginacaoClientes
        INTO @ContactName, @City
 
        WHILE @@FETCH_STATUS = 0
        BEGIN
            IF @QtdeInicial >= (@PagAtual * @QtdePagina) – @QtdePagina
            BEGIN
                INSERT INTO #ClientesTemp VALUES(@ContactName, @City)
                SET @Contador = @Contador + 1
 
                IF @Contador >= @QtdePagina
                    BREAK
            END
            SET @QtdeInicial = @QtdeInicial + 1
 
            FETCH NEXT FROM curPaginacaoClientes
               INTO @ContactName, @City
        END
 
    CLOSE curPaginacaoClientes
    DEALLOCATE curPaginacaoClientes
 
    SELECT ContactName, City FROM #ClientesTemp
 
    DROP TABLE #ClientesTemp
 
    SET NOCOUNT OFF
 
    SET @TotalClientes = (SELECT COUNT(CustomerID) FROM Customers)
GO
 
Código 1 – Stored Procedure “ResgataClientes”.

Como vemos no código acima, a Stored Procedure recebe dois parâmetros que é a página requisitada pelo Usuário e a quantidade de registros por página. Além disso, como dito anteriormente, existe um parâmetro de OUTPUT chamado @TotalClientes que e responsável por retornar a quantidade de Clientes para que seja possível efetuar os cálculos e assim exibindo corretamente a navegação da paginação.

Podemos ver também que é criado uma tabela temporária na linha 19, chamada #ClientesTemp, que é utilizada posteriormente, sendo populada com os registros necessários. Depois disso é criado um Cursor na linha 25 e através dele percorremos a tabela Customers e preenchemos a tabela temporária, anteriormente criada. Feito isso, fechamos o Cursor e o retiramos da memória, e retornamos ao cliente o resultado de um SELECT efetuado nesta tabela temporária na linha 51 e depois apagamos esta tabela (linha 53). E finalmente, apenas atribuimos ao parâmetro de saída a quantidade de registros da tabela Customers na linha 57.

Ainda é possível testá-la no Query Analyser, através do seguinte código:

1
2
3
 
DECLARE @TotalRegistros As Int
EXECUTE ResgatarClientes 10, [N], @TotalClientes = @TotalRegistros OUTPUT
PRINT @TotalRegistros
 
Código 2 – Testando a Stored Procedure “ResgataClientes” no Query Analyser.

Como vemos no código acima, o número 10 é a quantidade de registros por página e o [N] refere-se a página que o cliente está requerendo.

Feito isso, o próximo passo é partir para a aplicação ASP.NET, que irá utilizar esta Stored Procedure para popular e paginar os dados em um controle do tipo DataList. Devemos apenas arrastar em nosso WebForm o DataList e quatro controles do tipo LinkButton, que serão responsáveis pela navegação do usuário. Vamos incluir em nosso WebForm um Data Member que será responsável por armazenar a quantidade de registros por páginas:

1
 
Private _totalRegistrosPagina As Integer = 10
 
Código 3 – Definindo através de um Data Member a quantidade de registros por página.

Logo, temos que criar um procedimento que será responsável por popular o DataList. Esta função se chamará CarregaGrid, e terá como parâmetro um valor inteiro representando a página que o usuário está requerendo. Vejamos abaixo o código deste procedimento:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 
Private Sub CarregaGrid(ByVal paginaAtual As Integer)
    Dim conn As New SqlConnection(“CONNECTION_STRING”)
    Dim dr As SqlDataReader
    Dim cmd As New SqlCommand(“ResgatarClientes”, conn)
    cmd.CommandType = CommandType.StoredProcedure
 
    Dim paramQtdeRegistroPagina As SqlParameter
    paramQtdeRegistroPagina = New SqlParameter(“@QtdePagina”, SqlDbType.Int)
    paramQtdeRegistroPagina.Value = Me._totalRegistrosPagina
    cmd.Parameters.Add(paramQtdeRegistroPagina)
 
    Dim paramPaginaAtual As SqlParameter
    paramPaginaAtual = New SqlParameter(“@PagAtual”, SqlDbType.Int)
    paramPaginaAtual.Value = paginaAtual
    cmd.Parameters.Add(paramPaginaAtual)
 
    Dim paramTotalRegistros As SqlParameter
    paramTotalRegistros = New SqlParameter(“@TotalClientes”, SqlDbType.Int)
    paramTotalRegistros.Direction = ParameterDirection.Output
    cmd.Parameters.Add(paramTotalRegistros)
 
    Try
        conn.Open()
        dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)
        If dr.HasRows() Then
            With Me.dtlDados
                .DataSource = dr
                .DataBind()
            End With
            Me.lblPaginaCorrente.Text = paginaAtual
        End If
    Catch ex As Exception
        Response.Write(ex.ToString)
    Finally
        If Not (dr Is Nothing) Then
            dr.Close()
        End If
        Call Me.ControlePaginacao(cmd.Parameters(“@TotalClientes”).Value)
    End Try
End Sub
 
Código 4 – Procedimento CarregaGrid().

Analisando o código acima, criamos os parâmetros referente à quantidade de registros por página e a página requerida pelo Usuário e também definimos o parâmetro de OUTPUT chamado @TotalClientes, qual retorna a quantidade total de registros. Depois disso, verificamos se é retornado algum registro através da propriedade HasRows(), que retorna True, caso encontrado algum registro, e com isso populamos o DataList com este DataReader, e depois de fechado o DataReader, recuperamos o valor do parâmetro OUTPUT e invocamos o procedimento ControlePaginacao, que é responsável por exibir a quantidade de páginas e a página atual para o Usuário.

O procedimento ControlePaginacao recebe como parâmetro a quantidade total de Clientes, e baseado nisso, exibe a quantidade total de páginas e a página atual em que o Usuário se encontra:

1
2
3
4
5
6
7
 
Private Sub ControlePaginacao(ByVal totalClientes As Integer)
    If (totalClientes Mod Me._totalRegistrosPagina) = 0 Then
        Me.lblTotal.Text = totalClientes / Me._totalRegistrosPagina
    Else
        Me.lblTotal.Text = Convert.ToInt32((totalClientes / Me._totalRegistrosPagina) + 1)
    End If
End Sub
 
Código 5 – Procedimento ControlePaginacao.

Agora, no evento Page_Load do WebForm, devemos chamar o procedimento CarregaGrid, passando como parâmetro o número 1, que refere-se a primeira página, lembrando que devemos chamar este procedimento quando não for PostBack. O código abaixo ilustra isso:

1
2
3
4
5
6
 
Private Sub Page_Load(…) Handles MyBase.Load
    If Not Page.IsPostBack Then
        Call Me.CarregaGrid(1)
        Call Me.Navegacao(1)
    End If
End Sub
 
Código 6 – Evento Page_Load do WebForm.

Ainda temos mais um procedimento para criar, chamado Navegacao, procedimento qual se encarrega de habilitar/desabilitar os botões de navegação da paginação. Este procedimento também é baseado na página atual que está sendo exibida. Vejamos abaixo o código deste procedimento na íntegra:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
Private Sub Page_Load(ByVal paginaAtual As Integer)
    If paginaAtual = 1 Then
        With Me
            .lnkAnterior.Enabled = False
            .lnkProxima.Enabled = True
            .lnkPrimeiraPagina.Enabled = False
            .lnkUltimaPagina.Enabled = True
        End With
    ElseIf paginaAtual = Me.lblTotal.Text AndAlso paginaAtual > 1 Then
        With Me
            .lnkAnterior.Enabled = True
            .lnkProxima.Enabled = False
            .lnkPrimeiraPagina.Enabled = True
            .lnkUltimaPagina.Enabled = False
        End With
    Else
        With Me
            .lnkAnterior.Enabled = True
            .lnkProxima.Enabled = True
            .lnkPrimeiraPagina.Enabled = True
            .lnkUltimaPagina.Enabled = True
        End With
    End If
End Sub
 
Código 7 – Procedimento Navegacao.

Depois disso, nosso controle ficará semelhante à imagem abaixo:

Figura 1 – Controle DataList já com os controles de Navegação pelas páginas.

Mas ainda resta codificarmos os eventos Click() dos LinkButton responsáveis pela navegação das páginas. Temos quatro LinkButtons com as seguintes funcionalidades:

  • < – Primeira página.
  • << – Página anterior.
  • >> – Próxima página.
  • > – Última página.
1
2
3
4
 
Private Sub lnkPrimeiraPagina_Click(…) Handles lnkPrimeiraPagina.Click
    Call Me.CarregaGrid(1)
    Call Me.Navegacao(1)
End Sub
 
Código 8 – Procedimento que retorna à primeira página.

 

1
2
3
4
 
Private Sub lnkUltimaPagina_Click(…) Handles lnkUltimaPagina.Click
    Call Me.CarregaGrid(Convert.ToInt32(Me.lblTotal.Text))
    Call Me.Navegacao(Convert.ToInt32(Me.lblTotal.Text))
End Sub
 
Código 9 – Procedimento que vai para a última página.

 

1
2
3
4
5
 
Private Sub lnkAnterior_Click(…) Handles lnkAnterior.Click
    Dim paginaAtual As Integer = Integer.Parse(Me.lblPaginaCorrente.Text.ToString()) – 1
    Call Me.CarregaGrid(Convert.ToInt32(paginaAtual)
    Call Me.Navegacao(Convert.ToInt32(paginaAtual)
End Sub
 
Código 10 – Procedimento que retorna à página anterior.

 

1
2
3
4
5
 
Private Sub lnkProxima_Click(…) Handles lnkProxima.Click
    Dim paginaAtual As Integer = Integer.Parse(Me.lblPaginaCorrente.Text.ToString()) + 1
    Call Me.CarregaGrid(Convert.ToInt32(paginaAtual)
    Call Me.Navegacao(Convert.ToInt32(paginaAtual)
End Sub
 
Código 11 – Procedimento vai para a página posterior.

Conclusão: Vimos neste artigo como resgatar os dados da base de dados através de uma Stored Procedure, mas limitando os dados da página a ser exibida para proporcionar performance, retornando os dados para uma aplicação ASP.NET, e populando um controle DataList, controlando e exibindo a paginação.

PaginandoDadosStoredProcedure.zip (22.51 kb)

Anúncios

9 comentários sobre “Paginando dados com DataList

  1. Poxa amigão obrigado por responder tão rapido , mas no meu caso tem qie ser o DataList pois pretendo fazer uma galeria de Imagens com com uma tabela de 10 linhas e 3 colunas, o GridView conheço bem mas não resolve meu problema obrigado pela dica.

    • Boa Noite,

      Israel, muito bom seu artigo, porem sou programador C# e não consigo fazer o mesmo na minha linguagem tem como você postar esse mesmo artigo em C#? fiz passo a passo mas não funciona andei usando componente mas não é a mesma coisa mesmo pq a maioria é pago prefiro aprender fazer na mão se tiver algum modelo em C# fico grato , obrigado.

    • Boas Heraldo,

      Recorre ao controle GridView que o ASP.NET já traz, que já possui a paginação nativa, onde com pequenas configurações, você atinge o mesmo resultado.

    • <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;

      <html xmlns="http://www.w3.org/1999/xhtml"&gt;
      <head runat="server">
      <title>Untitled Page</title>
      <style type="text/css">
      .style1
      {
      width: 47%;
      }
      </style>
      </head>
      <body>
      <form id="form1" runat="server">

      CustomerID:
      ‘ />

      ContactName:
      ‘ />

      City:
      ‘ />


      SelectCommand=”SELECT [CustomerID], [ContactName], [City] FROM [Customers]”>

      <Primeira

      <Anterior

      Proximo>

      Ultima>>

       

       

      </form>
      </body>
      </html>

    • olha o link pra ter uma ideia, esse é com conponente da DevExpress

      Por isso motivo que tem que ser DataList

    • Desculpa os erros de português também rs…vou tentar resolver isso, se conseguir gostaria que publicasse a solução no seu blog para que outros possam utilizar o modelo , pois como comentei antes não achei nada em C# que funcionasse com a simplicidade que seu em VB.NET funciona ok, Valew.

    • Bom Dia,

      Olá Israel tudo bem? resolvido o problema de paginação em C# com base no seu modelo, um amigo achou o erro que eu não tinha visto alias dois erros segue modelo, para analise.

      Valew.

    • C#

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Web;
      using System.Web.UI;
      using System.Web.UI.WebControls;
      using System.Data.SqlClient;
      using System.Data;
      public partial class _Default : System.Web.UI.Page
      {
      string _connectionString = "Data Source=NS01111;Initial Catalog=DADOS;User ID=admin;Password=admin";
      int _totalRegistrosPagina = 10;
      protected void Page_Load(object sender, EventArgs e)
      {

      if (!Page.IsPostBack)
      {

      CarregaGrid(1);
      Navegacao(1);

      }
      }

      public void CarregaGrid(int paginaAtual)
      {
      SqlConnection conn = new SqlConnection(_connectionString);
      SqlDataReader dr;
      SqlCommand cmd = new SqlCommand("ResgatarClientes", conn);
      cmd.CommandType = CommandType.StoredProcedure;

      SqlParameter paramQtdeRegistroPagina;
      paramQtdeRegistroPagina = new SqlParameter("@QtdePagina", SqlDbType.Int);
      paramQtdeRegistroPagina.Value = _totalRegistrosPagina;
      cmd.Parameters.Add(paramQtdeRegistroPagina);
      SqlParameter paramPaginaAtual;
      paramPaginaAtual = new SqlParameter("@PagAtual", SqlDbType.Int);
      paramPaginaAtual.Value = paginaAtual;
      cmd.Parameters.Add(paramPaginaAtual);
      SqlParameter paramTotalRegistros;
      paramTotalRegistros = new SqlParameter("@TotalClientes", SqlDbType.Int);
      paramTotalRegistros.Direction = ParameterDirection.Output;
      cmd.Parameters.Add(paramTotalRegistros);
      try
      {
      conn.Open();
      dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
      if (dr.HasRows == true)
      {
      dtlDados.DataSource = dr;
      dtlDados.DataBind();
      lblPaginaCorrente.Text = paginaAtual.ToString();
      }
      }
      catch (Exception ex)
      {
      Response.Write(ex.ToString());
      }
      finally
      {

      /* if (dr.HasRows == false)
      {
      dr.Close();
      }*/
      ControlePaginacao(int.Parse(paramTotalRegistros.Value.ToString()));
      }
      }
      public void ControlePaginacao(int totalClientes)
      {
      if (totalClientes % _totalRegistrosPagina == 0)
      {
      lblTotal.Text = (totalClientes / _totalRegistrosPagina).ToString();
      }
      else
      {
      lblTotal.Text = ((totalClientes / _totalRegistrosPagina) + 1).ToString();
      }
      }
      private void Navegacao(int paginaAtual)
      {
      if (paginaAtual == 1)
      {
      {
      lnkAnterior.Enabled = false;
      lnkProxima.Enabled = true;
      lnkPrimeiraPagina.Enabled = false;
      lnkUltimaPagina.Enabled = true;
      }
      }
      else if (paginaAtual == Convert.ToUInt32(lblTotal.Text) && paginaAtual > 1)
      {
      {
      lnkAnterior.Enabled = true;
      lnkProxima.Enabled = false;
      lnkPrimeiraPagina.Enabled = true;
      lnkUltimaPagina.Enabled = false;
      }
      }
      else
      {
      {
      lnkAnterior.Enabled = true;
      lnkProxima.Enabled = true;
      lnkPrimeiraPagina.Enabled = true;
      lnkUltimaPagina.Enabled = true;
      }
      }
      }
      protected void lnkPrimeiraPagina_Click(object sender, EventArgs e)
      {

      }
      protected void lnkUltimaPagina_Click(object sender, EventArgs e)
      {

      }
      protected void lnkAnterior_Click(object sender, EventArgs e)
      {

      }
      protected void lnkProxima_Click(object sender, EventArgs e)
      {

      }
      protected void lnkProxima_Click1(object sender, EventArgs e)
      {
      int paginaAtual = int.Parse(lblPaginaCorrente.Text.ToString()) + 1;
      CarregaGrid(paginaAtual);
      Navegacao(paginaAtual);
      }
      protected void lnkUltimaPagina_Click1(object sender, EventArgs e)
      {
      CarregaGrid(Convert.ToInt32(lblTotal.Text));
      Navegacao(Convert.ToInt32(lblTotal.Text));

      }
      protected void lnkAnterior_Click1(object sender, EventArgs e)
      {
      int paginaAtual = int.Parse(lblPaginaCorrente.Text.ToString()) – 1;
      CarregaGrid(paginaAtual);
      Navegacao(paginaAtual);
      }
      protected void lnkPrimeiraPagina_Click1(object sender, EventArgs e)
      {
      CarregaGrid(1);
      Navegacao(1);
      }
      }

      aspx

      <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;

      <html xmlns="http://www.w3.org/1999/xhtml"&gt;
      <head runat="server">
      <title></title>
      <style type="text/css">

      .style2
      {
      height: 33px;
      }
      .style1
      {
      height: 25px;
      }
      </style>
      </head>
      <body>
      <form id="form1" runat="server">
      <table align="center" width="100%">
      <tr>
      <td align="center">
      <asp:DataList ID="dtlDados" runat="server" BackColor="White"
      BorderColor="#999999" BorderStyle="None" BorderWidth="1px" CellPadding="3"
      GridLines="Vertical" Width="100%">
      <SelectedItemStyle BackColor="#008A8C" Font-Bold="True" ForeColor="White" />
      <AlternatingItemStyle BackColor="#DCDCDC" />
      <ItemStyle BackColor="#EEEEEE" ForeColor="Black" />
      <ItemTemplate>
      <table align="center" width="100%">
      <tr>
      <td width="50%">
      <%# DataBinder.Eval(Container.DataItem, "ContactName")%>
      </td>
      <td width="50%">
      <%# DataBinder.Eval(Container.DataItem, "City")%>
      </td>
      </tr>
      </table>
      </ItemTemplate>
      <FooterStyle BackColor="#CCCCCC" ForeColor="Black" />
      <HeaderStyle BackColor="#000084" Font-Bold="True" ForeColor="White" />
      <AlternatingItemTemplate>
      <table align="center" width="100%">
      <tr>
      <td width="50%">
      <%# DataBinder.Eval(Container.DataItem, "ContactName")%>
      </td>
      <td width="50%">
      <%# DataBinder.Eval(Container.DataItem, "City")%>
      </td>
      </tr>
      </table>
      </AlternatingItemTemplate>
      </asp:DataList>
      </td>
      </tr>
      <tr>
      <td align="right" class="style2">
      <table cellpadding="2" cellspacing="2">
      <tr>
      <td class="style1">
      (Pagina
      <asp:Label ID="lblPaginaCorrente" Runat="server"></asp:Label>
      &nbsp;de
      <asp:Label ID="lblTotal" Runat="server"></asp:Label>
      )
      </td>
      <td class="style1">
      <asp:LinkButton ID="lnkPrimeiraPagina" runat="server"
      onclick="lnkPrimeiraPagina_Click1">&lt; Primeira</asp:LinkButton>
      &nbsp;<asp:LinkButton ID="lnkAnterior" Runat="server" onclick="lnkAnterior_Click1"
      title="Click here to display the previous page of clients.">&lt;&lt; Anterior</asp:LinkButton>
      &nbsp;
      <asp:LinkButton ID="lnkProxima" Runat="server" onclick="lnkProxima_Click1"
      title="Click here to display the next page of clients."> Proxima &gt;&gt;</asp:LinkButton>
      &nbsp;
      <asp:LinkButton ID="lnkUltimaPagina" runat="server"
      onclick="lnkUltimaPagina_Click1">Ultima &gt;</asp:LinkButton>
      </td>
      </tr>
      </table>
      </td>
      </tr>
      </table>
      </form>
      </body>
      </html>

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s