Effective Paging and Sorting Using GridView and ObjectDataSource – Part I
With ObjectDataSource, you can do paging and sorting very effectively in gridview. In real time, we have millions of records in database. At that time, when we have to fetch those records and display in grid will take more time which makes performance issue. For this purpose, objectDataSource provide an good option for using paging and sorting in gridview. I had taken help from asp.net book and modify some of things.
Download source code here.
Paging :-
Notice that the objectDataSource control includes as EnablePaging property that has value True. The ObjectDataSource also includes a SelectCountMethod property that represents the name of a method that retrieves a record count from the data source. Even when using data source paging, you still need to enable AllowPaging property to True and using PageSize property.
When an ObjectDataSource control has its EnablePaging property set to the value True, the ObjectDataSource passes additional parameters when calling the method represented by its SelectMethod property. The two additional parameters are named StartRowIndex and MaximumRows, this parameter will be added implicitly.
To improve performance, the GetCustomerCount() method attempts to retrieve the total count from server cache. If the record count cannot be retrieved from the cache, the count is retrieved from the DB.
At store procedure side, we can use Row_Number() function to select a range of rows. Note that Row_Number() available above Sql Server 2005 versions only.
Property Use for paging in ObjectDataSource is SelectCountMethod and EnablePaging.
here more logic is at store procedure side then coding side. So mainly I will explain store procedure. and provide code at the end.
WITH ( SELECT CustomerID, ROW_NUMBER() OVER (ORDER BY CustomerID) AS RowNo FROM CUSTOMER ) SELECT Customer.CustomerID, Customer.FirstName, Customer.MiddleName, Customer.LastName, Customer.Desgination, Customer.Address, Customer.City, Customer.State, Customer.Country FROM CustDetails INNER JOIN Customer ON CustDetails.CustomerID = Customer.CustomerID WHERE (RowNo BETWEEN @StartRowIndex + 1 AND @StartRowIndex + @MaximumRows + 1) |
with clause is used for getting customer details with ROW_NUMBER() function to get row number wise. Then finally using inner join with CET table and customer table and fetching row that has been passed in SP between @StartRowIndex and @MaximumRows.
Sorting :-
For sorting, ObjectDataSource control includes a property named SortParameterName. Note, this is just the portion of the query for sorting. You can download full store procedure script which link has been given below.
SELECT Customer.CustomerID, Customer.FirstName, Customer.MiddleName, Customer.LastName, Customer.Desgination, Customer.Address, Customer.City, Customer.State, Customer.Country FROM CustDetails INNER JOIN Customer ON CustDetails.CustomerID = Customer.CustomerID ORDER BY CASE WHEN @SortExpression='CustomerID' THEN Customer.CustomerID END ASC, CASE WHEN @SortExpression='CustomerID DESC' THEN Customer.CustomerID END DESC |
Notice that the store procedure uses SQL CASE function to sort the records before they are added to query. Unfortunately, you can’t use a parameter with an ORDER BY clause, so the sort columns must be hard-coded in the CASE functions.
Html markup look for gridview look like below.
<div> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <asp:GridView ID="gvPagingSorting" DataSourceID="Customer" AllowSorting="true" AllowPaging="true" PageSize="5" DataKeyNames="CustomerID" runat="server" CellPadding="4" ForeColor="#333333" GridLines="None"> <RowStyle BackColor="#F7F6F3" ForeColor="#333333" /> <FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" /> <PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" /> <SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" /> <HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" /> <EditRowStyle BackColor="#999999" /> <AlternatingRowStyle BackColor="White" ForeColor="#284775" /> </asp:GridView> <asp:ObjectDataSource ID="Customer" TypeName="ObjCustomer" SortParameterName="SortExpression" SelectCountMethod="GetCustomerCount" EnablePaging="true" SelectMethod="GetCustomer" runat="server"/> </ContentTemplate> </asp:UpdatePanel> </div> |
objCustomer class look like below
using System; using System.Web; using System.Data; using System.Data.SqlClient; using System.Web.Configuration;
public class ObjCustomer { private readonly string conStr; public ObjCustomer() { conStr = WebConfigurationManager.ConnectionStrings["MyBlogConnectionString"].ConnectionString; }
public SqlDataReader GetCustomer(int StartRowIndex, int MaximumRows, String SortExpression) { try { SqlConnection con = new SqlConnection(conStr); SqlCommand cmd = new SqlCommand("GetCustomer", con); cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@StartRowIndex",StartRowIndex); cmd.Parameters.AddWithValue("@MaximumRows",MaximumRows); cmd.Parameters.AddWithValue("@SortExpression", SortExpression); con.Open(); return cmd.ExecuteReader(CommandBehavior.CloseConnection); } catch (Exception ex) { throw ex; } }
public int GetCustomerCount() { try { HttpContext context = HttpContext.Current;
if (context.Cache["CustomerCount"] == null) { SqlConnection con = new SqlConnection(conStr); string sqlQuery = "SELECT COUNT(CUSTOMERID) FROM [Customer]"; SqlCommand cmd = new SqlCommand(sqlQuery, con); cmd.Connection.Open(); context.Cache["CustomerCount"] = (int)cmd.ExecuteScalar(); ; }
return (int)context.Cache["CustomerCount"]; } catch (Exception ex) { throw ex; } } } |
Explanation of class file :-
GetCustomer() method pass three parameters, StartRowIndex, MaximumRows and SortExpression. First two parameter used for paging and last parameter used for sorting. GetCustomer() method used for ObjectDataSource property SelectMethod. GetCustomerCount() method used for getting total count for customer from DB. GetCustomerCount() method used for ObjectDataSource property SelectCountMethod.
Note :- One important thing to note about GetCustomer() method is that, return type of method is SqlDataReader(forward-read only) which will also help in improving performance. Of course, returning only grid pagesize should not be major problem even if you use datatable or dataset. Just once I remember user asking question in asp.net forum, whether its possible paging with datareader ?. So, I think this is the answer. |
Output looks like below :-
Hope you like this article.
Kindly Note down changes for this article made on 24th nov 2009
I had modify the store procedure to work correctly with sorting for all grid pages. Previously, only current page was sorting by that field for that particular page size. And, next page will sort again. So, I modify that store procedure which i change download link on top. And re-writing procedure down also
ALTER PROC [dbo].[GetCustomer] ( @StartRowIndex INT, @MaximumRows INT, @SortExpression VARCHAR(100) ) AS WITH ( SELECT CustomerID, ROW_NUMBER() OVER (ORDER BY CASE WHEN @SortExpression='CustomerID' THEN Customer.CustomerID END ASC, CASE WHEN @SortExpression='CustomerID DESC' THEN Customer.CustomerID END DESC,
CASE WHEN @SortExpression='FirstName' THEN Customer.FirstName END ASC, CASE WHEN @SortExpression='FirstName DESC' THEN Customer.FirstName END DESC,
CASE WHEN @SortExpression='MiddleName' THEN Customer.MiddleName END ASC, CASE WHEN @SortExpression='MiddleName DESC' THEN Customer.MiddleName END DESC,
CASE WHEN @SortExpression='LastName' THEN Customer.LastName END ASC, CASE WHEN @SortExpression='LastName DESC' THEN Customer.LastName END DESC,
CASE WHEN @SortExpression='Desgination' THEN Customer.Desgination END ASC, CASE WHEN @SortExpression='Desgination DESC' THEN Customer.Desgination END DESC,
CASE WHEN @SortExpression='Address' THEN Customer.Address END ASC, CASE WHEN @SortExpression='Address DESC' THEN Customer.Address END DESC,
CASE WHEN @SortExpression='City' THEN Customer.City END ASC, CASE WHEN @SortExpression='City DESC' THEN Customer.City END DESC,
CASE WHEN @SortExpression='State' THEN Customer.State END ASC, CASE WHEN @SortExpression='State DESC' THEN Customer.State END DESC,
CASE WHEN @SortExpression='Country' THEN Customer.Country END ASC, CASE WHEN @SortExpression='Country DESC' THEN Customer.Country END DESC) AS RowNo FROM CUSTOMER
) SELECT Customer.CustomerID, Customer.FirstName, Customer.MiddleName, Customer.LastName, Customer.Desgination, Customer.Address, Customer.City, Customer.State, Customer.Country FROM CustDetails INNER JOIN Customer ON CustDetails.CustomerID = Customer.CustomerID WHERE (RowNo BETWEEN @StartRowIndex + 1 AND @StartRowIndex + @MaximumRows + 1) |