Link to home
Start Free TrialLog in
Avatar of ratul keot
ratul keot

asked on

Paginate database records using stored procedure

Hi, I have a blog website build using ASP.NET using C# and entity framework.
I have this requirement where I need to list all my published blogs and paginate them as they are too many.
I am new to .NET and have no idea how to do it.

Earlier I got all the blog details from the database and used ajax and JSON as well to fetch it.

A friend gave me a sample code and told me it would help. Please have a look into that as well.


Please help me acheive this.
I am attaching all my code here along with the stored procedure.


STORED PROCEDURE

GO
/****** Object:  StoredProcedure [dbo].[GetBlogs]    Script Date: 05-11-2018 01:50:14 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER proc [dbo].[GetBlogs]

@count int,
@start int,
@categoryId int,
@blogCount int Output
as
begin
	Declare @LastBlog int
	Set @count = 9
	Set @lastBlog = @count + @start;

	create table #x (id int identity(1,1),blogid int)

	if @categoryId is null
		begin
			insert into #x
			select Id from Blog where IsDeleted=0 and StatusId = 2

		end
	else
		begin
			insert into #x	
			select b.Id from Blog b inner join BlogCategories bc on b.Id = bc.BlogId where bc.CategoryId = @categoryId and b.IsDeleted=0 and b.StatusId = 2;
		end
	
	select @blogCount = COUNT(#x.id) from #x 

	select b.* from #x inner join Blog b on #x.blogid = b.Id where #x.id > @start and #x.id <= @LastBlog

	drop table #x

end

Open in new window




DAL Sample Code

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Linq;
using System.Text;

namespace Project.Utility
{
   public class DAL
    {
        #region Variables

        public static bool? IsStoredProc = null;
        public static int CommandTimeoutSeconds = 240;
        public static string ConnectionString = ConfigurationManager.ConnectionStrings["BlogDataModel"].ConnectionString;

        #endregion Variables

        #region Port Methods

        protected static DbConnection CmnDbConnection(string connStr)
        {
            return new SqlConnection(connStr);
        }

        protected static DbCommand CmnDbCommand(string query, DbConnection connection)
        {
            
                return new SqlCommand(query, connection as SqlConnection);
        }

        public static DbDataAdapter CmnDbDataAdapter(DbCommand command)
        {
            return new SqlDataAdapter(command as SqlCommand);
        }

        public static DbParameter CmnDbParameter(string name, object value)
        {
            return new SqlParameter(name, value);
        }

        #endregion Port Methods

        #region Methods
        public static DataTable Read(string query, DbParameter[] paramList, bool? isStoredProc, int? timeout)
        {
            DataTable dt = new DataTable();
            using (DbConnection connection = CmnDbConnection(ConnectionString))
            {
                try
                {
                    DbCommand command = CmnDbCommand(query, connection);
                    if (isStoredProc != null)
                    {
                        command.CommandType = isStoredProc.Value ? CommandType.StoredProcedure : CommandType.Text;
                    }
                    if (isStoredProc != null && isStoredProc == true)
                    {
                        if(paramList!=null)
                        {
                            command.Parameters.AddRange(paramList);
                        }
                    }

                    command.CommandTimeout = timeout ?? CommandTimeoutSeconds;

                    DbDataAdapter adapter = CmnDbDataAdapter(command);
                    adapter.SelectCommand.Connection.Open();
                    adapter.Fill(dt);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
            }
            return dt;
        }

        public static int Insert(string query, int? timeout)
        {
            int returnValue = 0;
            using (DbConnection connection = CmnDbConnection(ConnectionString))
            {
                try
                {
                    DbCommand command = CmnDbCommand(query, connection);
                    command.CommandTimeout = timeout ?? CommandTimeoutSeconds;

                    DbDataAdapter adapter = CmnDbDataAdapter(command);
                    adapter.InsertCommand = command;
                    adapter.InsertCommand.Connection.Open();
                    adapter.InsertCommand.ExecuteNonQuery();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
            }
            return returnValue;
        }

        #endregion

    }
}

Open in new window



I hope I am able to explain the situation clearly. I can provide more data If required.
Avatar of Russ Suter
Russ Suter

It sounds to me like you need a paged query. You can do all of this easily without needing temp tables and performance will be fine as long as your table is properly indexed. Add a @PageNumber argument to your stored procedure and optionally a @PageSize argument then just select like this:

SELECT
    *
FROM
    MyTable
WHERE
    -- something
ORDER BY
    --something
OFFSET @PageSize * (@PageNumber - 1) ROWS -- because OFFSET is zero indexed and you probably want human readable page numbers starting with 1
FETCH NEXT @PageSize ROWS ONLY OPTION (RECOMPILE)

Open in new window

Avatar of ratul keot

ASKER

@Russ Suter- Thanks for the suggestion. I would be grateful if you could show me how to get the data from the stored procedure to the the asp page. I have no clue how to get it. Thank you
I would not use the record ID to paginate because the ID may not always be sequential.  A failed insert or deleted record would produce a gap in the ID sequence. Instead use ...psuedo code:   SELECT TOP 9 * FROM @tablename WHERE ID NOT IN(SELECT TOP (9 * (@pagenumber -1)) ID FROM @tablename) ORDER BY ID desc
If you are merely looking at statistical data,
Count of records/number of records per page.
I.e. Two queries, one determines row count, one displays .......the requested page.

The following might be another..

http://www.sqlservergeeks.com/sql-server-alternatives-to-top-clause-rowcount-row_number/
Assuming you have a working stored procedure that accepts the @PageNumber argument (@PageSize can easily be a passed variable or a value that is set inside the stored procedure itself), you'd need a SQL Data Connection and a SQL Data Adapter. Your C# code would look something like this:
			using (SqlConnection connection = new SqlConnection("[insert your connection string here]"))
			{
				using (SqlDataAdapter da = new SqlDataAdapter("GetBlogs", connection))
				{
					DataTable dt = new DataTable();
					da.SelectCommand.Parameters.AddWithValue("@Count", 1);
					da.SelectCommand.Parameters.AddWithValue("@start", 1);
					da.SelectCommand.Parameters.AddWithValue("@categoryId", 1);
					da.SelectCommand.Parameters.AddWithValue("@blogCount", 100);
					da.Fill(dt);
					return dt;
				}
			}

Open in new window

I'm assuming in your stored procedure example you're using @start as the page number and @blogCount as the page size. Of course you'd need to pass useful variable values rather than constants as I have in this example.

What you end up with is a data table that contains the requested data. You can then drop that data table into any control that supports DataBinding or manipulate it however you wish.
Here is a ROW_NUMBER() example for efficiently paging through large amounts of data.

 This example is as simple as it gets and plays very well with large tables. Let me know if you need any help getting this sample working with your tables.

It's highly simplified vs. the article, but I made this example for you using the information found at this link.
https://docs.microsoft.com/en-us/previous-versions/dotnet/articles/bb445504(v=msdn.10)

T-SQL stored procedure.
USE [yourdb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Create PROCEDURE [dbo].[pagedisplay] (
     @Page int,
     @RecsPerPage int
        )
AS
SET ROWCOUNT @RecsPerPage
DECLARE @TCount bigint
select @TCount = COUNT(*)from dbo.testtable
BEGIN

WITH USERPAGE AS
(
SELECT ROW_NUMBER() OVER (Order By registered DESC) AS RowNum
,[userid]
,[registered]
,@TCount as 'TotalCount'
 FROM dbo.testtable with (Nolock)  
) 

SELECT * 
FROM USERPAGE
WHERE RowNum BETWEEN (@Page - 1) * @RecsPerPage + 1 AND @Page * @RecsPerPage Order By registered DESC
END

Open in new window


C# pagetest.aspx.
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data.SqlClient" %>

<% 
//edit me
SqlConnection Conn = new SqlConnection("Server=127.0.0.1;Database=yourdb;UID=user;PWD=pass;");
int PageSize = 100;
//end edit me

String Number = "";
int PNumber = 0;
int CurPage = 1;

if ((Request["Page"] != null) && (Request["Page"] != "")) {
try{CurPage = Convert.ToInt32(Request["Page"]);}
catch { CurPage = 1; }
}

Conn.Open();
SqlCommand Ulook = new SqlCommand("pagedisplay @Page='" + CurPage + "', @RecsPerPage='" + PageSize + "'", Conn);
SqlDataReader UlookSet = Ulook.ExecuteReader();
while (UlookSet.Read()) {Number = UlookSet["TotalCount"].ToString(); } //write your data in that while loop etc.. UlookSet["userid"].ToString() and UlookSet["registered"].ToString() in this example.
UlookSet.Close();
Ulook.Dispose();
Conn.Close();
Conn.Dispose();

try{ PNumber = Convert.ToInt32(Math.Ceiling(Convert.ToDecimal(Number) / Convert.ToDecimal(PageSize))); }
catch { PNumber = 1; }
if (PNumber <= 0) { PNumber = 1; }
int TotalPages = PNumber;
int i = CurPage + 1;
int j = CurPage - 1;
int TPO = CurPage - 6;

Response.Write(" Page " + CurPage + "  of " + TotalPages + "<br/>");
if (CurPage != 1){ Response.Write(" <a href=pagetest.aspx?page=" + j + ">Previous</a> | "); }
  for (int k = 1; k <= 12; k++){
if ((TPO > 1) && (TPO < TotalPages)) { 
if (TPO != CurPage){Response.Write(" <a href=pagetest.aspx?page=" + TPO + ">" + TPO + "</a> "); }
else {Response.Write(" [" + TPO + "] ");}
TPO++;
}
}
if ((TotalPages > 1) && (i <= TotalPages)) { Response.Write("| <a href=pagetest.aspx?page=" + i + ">Next</a>");  }

%>

Open in new window


Sample table
USE [yourdb]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[testtable](
	[userid] [nvarchar](50) NOT NULL,
	[registered] [datetime] NULL,
	 CONSTRAINT [PK_testtable] PRIMARY KEY CLUSTERED 
(
	[userid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]

GO

Open in new window

This question needs an answer!
Become an EE member today
7 DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform.
View membership options
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.