Labels

Wednesday, January 13, 2010

Custom Paging - Two Approaches

 

METHOD 1 :-

 

One disadvantage of using the DataGrid control's built-in paging support is performance. When you use the method of paging through records discussed in the preceding section, all the records must be retrieved from the data source every time you navigate to a new page. So, if you are paging through a database table with 2 million records, those 2 million records must be retrieved into memory every time you move to a new page.

 

The custom paging solution you examine here makes a strong assumption about the contents of the database table with which it is used. This approach works only with database tables, that have a column that uniquely indexes each database row.

 

CAUTION

 

If certain values are missing from the identity column, the DataGrid displays fewer records for some pages than others.

Listing 11.20 DataGridCustomPaging.aspx

<%@ Import Namespace="System.Data.SqlClient" %>

<%@ Import Namespace="System.Data" %>

 

<Script Runat="Server">

 

Dim conNorthwind As SqlConnection

Dim strSelect As String

Dim intStartIndex As Integer

Dim intEndIndex As Integer

 

Sub Page_Load

  Dim cmdSelect As SqlCommand

 

  conNorthwind = New SqlConnection( "" )

  If Not IsPostBack Then

    ' Get Total Pages

    strSelect = "Select Count(*) From Products"

    cmdSelect = New SqlCommand( strSelect, conNorthwind )

    conNorthwind.Open()

    dgrdProducts.VirtualItemCount = ( cmdSelect.ExecuteScalar() / dgrdProducts.PageSize )

    conNorthwind.Close()

    BindDataGrid   // First Time

  End If

End Sub

 

Sub BindDataGrid

  Dim dadProducts As SqlDataAdapter

  Dim dstProducts As DataSet

 

  intEndIndex = intStartIndex + dgrdProducts.PageSize

  strSelect = "Select * From Products Where ProductID > @startIndex " _

    & "And ProductID <= @endIndex Order By ProductID"

 

  dadProducts = New SqlDataAdapter( strSelect, conNorthwind )

  dadProducts.SelectCommand.Parameters.Add( "@startIndex", intStartIndex )

  dadProducts.SelectCommand.Parameters.Add( "@endIndex", intEndIndex )

  dstProducts = New DataSet

  dadProducts.Fill( dstProducts )

 

  dgrdProducts.DataSource = dstProducts

  dgrdProducts.DataBind()

End Sub

 

 

Sub dgrdProducts_PageIndexChanged( s As Object, e As DataGridPageChangedEventArgs )

  intStartIndex = (( e.NewPageIndex – 1) * dgrdProducts.PageSize )) + 1     

  dgrdProducts.CurrentPageIndex = e.NewPageIndex

  BindDataGrid   // From next Time

End Sub

 

</Script>

 

 

A count of the total number of records in the Products table is retrieved in the Page_Load subroutine. This value is assigned to the VirtualItemCount property of the DataGrid. The DataGrid control uses this property when rendering the paging links.

 


METHOD 2 :-
 

In this approach we are not following the assumption we require in the first method as :

 

“The custom paging solution you examine here makes a strong assumption about the contents of the database table with which it is used. This approach works only with database tables, that have a column that uniquely indexes each database row”.

Listing 11.20 DataGridCustomPaging.aspx

<%@ Import Namespace="System.Data.SqlClient" %>

<%@ Import Namespace="System.Data" %>

 

<Script Runat="Server">

 

Dim conNorthwind As SqlConnection

Dim strSelect As String

Dim intStartIndex As Integer =1

Dim intEndIndex As Integer

 

Sub Page_Load

  Dim cmdSelect As SqlCommand

 

  conNorthwind = New SqlConnection("")

  If Not IsPostBack Then

    ' Get Total Pages

    strSelect = "Select Count(*) From Products"

    cmdSelect = New SqlCommand( strSelect, conNorthwind )

    conNorthwind.Open()

    dgrdProducts.VirtualItemCount = ( cmdSelect.ExecuteScalar() / dgrdProducts.PageSize )

    conNorthwind.Close()

    BindDataGrid(1)   // First Time

  End If

End Sub

 

private Function BindDataGrid(nStartIndex As Integer)

 

            Dim strConn As String = "DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;"

            Dim conn As SqlConnection = New SqlConnection(strConn)

 

            ' FetchEmployeesByPage is a CUSTOM Northwind stored procedure

            ' that returns each single record in a different resultset. This is due

            ' to the use of T-SQL cursors

 

            Dim strCmd As String = "FetchEmployeesByPage"

            Dim da As SqlDataAdapter = New SqlDataAdapter()

            Dim cmd As SqlCommand = New SqlCommand(strCmd, conn)

            cmd.CommandType = CommandType.StoredProcedure

            da.SelectCommand = cmd

 

            Dim prmStartNumber As SqlParameter = New SqlParameter"@StartIndex", SqlDbType.Int)

            prmStartNumber.Direction = ParameterDirection.Input

            prmStartNumber.Value = nStartIndex

            cmd.Parameters.Add(prmStartNumber)

 

            Dim prmPageSize As SqlParameter = New SqlParameter("@PageSize", SqlDbType.Int)

            prmPageSize.Direction = ParameterDirection.Input

            prmPageSize.Value = grid.PageSize

            cmd.Parameters.Add(prmPageSize)

           

            ' Execute the command

            Dim ds As DataSet = New DataSet()

            da.Fill(ds)

 

            ' Merges the different resultsets(Each containing one record) in a single table

            Dim dsOutputTable As DataTable = ds.Tables(0).Clone()

            Dim dTable As DataTable

            Dim drow As DataRow

 

            For Each dTable In ds.Tables

                        For Each drow In dTable.Rows

 

                                    Dim tmp As DataRow = dsOutputTable.NewRow()

                                    tmp.ItemArray = drow.ItemArray

                                    dsOutputTable.Rows.Add(tmp)

                        Next

            Next

                       

            grid.DataSource = dsOutputTable

            grid.DataBind()

End Function

 

 

Sub dgrdProducts_PageIndexChanged( s As Object, e As DataGridPageChangedEventArgs )

  intStartIndex = (( e.NewPageIndex – 1) * dgrdProducts.PageSize )) + 1     

  dgrdProducts.CurrentPageIndex = e.NewPageIndex

  BindDataGrid(intStartIndex)   // From next Time

End Sub

 

</Script>

 

 

 

That procedure uses T-SQL cursors to return a page of records.

CREATE PROCEDURE FetchEmployeesByPage (@StartIndex smallint, @PageSize smallint)

AS

 

-- @StartIndex, Index of First record to fetch on each page

-- @PageSize, records that fit into one page

 

-- internal variables

  DECLARE @MyIndex smallint

  DECLARE @FirstRecPos smallint

 

-- sets the position of the first record to retrieve in the page

  SET @FirstRecPos = @StartIndex

 

-- cursor associated with the query string

  DECLARE employees_cursor SCROLL CURSOR FOR

            SELECT employeeid,firstname,lastname FROM employees

            ORDER BY lastname

 

-- opens the cursor

  OPEN employees_cursor

 

-- fetches the first record in the page

  FETCH ABSOLUTE @FirstRecPos FROM employees_cursor

 

-- loops through the cursor to pick up the other records in the page

  SET @MyIndex = 1

  WHILE @@FETCH_STATUS = 0 AND @MyIndex < @PageSize

  BEGIN

     FETCH NEXT FROM employees_cursor

     SET @MyIndex = @MyIndex + 1

  END

 

-- clean up

  CLOSE employees_cursor

  DEALLOCATE employees_cursor

GO

 

 

Hope this helps.

 

Regards,

Arun Manglick



Disclaimer: The information contained in this message may be privileged, confidential, and protected from disclosure. If you are not the intended recipient, or an employee, or agent responsible for delivering this message to the intended recipient, you are hereby notified that any dissemination, distribution, or copying of this communication is strictly prohibited. If you have received this communication in error, please notify us immediately by replying to the message and deleting it from your computer.

No comments:

Post a Comment