ASP .NET 如何在 SQL 查询层面实现分页
【编者按】本文作者为来自巴基斯坦的软件开发工程师 Aqeeel,主要介绍了在 SQL 查询层面实现 ASP.NET 应用的分页方法。
本文系 OneAPM 工程师编译呈现,以下为正文。
GridView 提供了一种实现分页的方法。但是,随着记录的不断扩大,我们需要在查询层面进行优化。
简介
在 SQL 查询层面实现 ASP.NET 程序分页,而不借助 GridView。
背景
无可否认,GridView 是在 ASP.NET Web 表单展示数据的强大工具,它能在结果集较大时实现分页。然而,后端会获取完整的数据,抽取出相关数据,然后通过 GridView 展示在 Web 表单中。在这种情况下,相关数据只是完全抽取数据的一小部分。这些多余的数据造成了处理能力、内存空间以及时间的极大浪费。在本文中,我们将展示如何仅从数据库抽取所需数据,从而避免这些浪费。
下图展示了从数据库中获取完整数据的方式。在渲染阶段,相关数据会被抽取出来,填充到 GridView 中。
下图展示了从数据库中抽取过滤或相关数据的方式,进而得到更小的数据集。在 Web 应用中,同样的数据集无需经过进一步抽取,就可以填充到 GridView 中。
具体实现
工具
本例借助 SQL Server 2014 与 Visual Studio 2015 实现。2012 之前的 SQL Server 版本不支持 FETCH,但是使用 ROW NUMBER 可以达到同样的效果。
首先进行后端设置:
- 创建名为 TestPagingInASPNET 的数据库,
- 创建名为 AdministrativeUnits 与 Cities 的两张表。
- 创建存储过程(Stored Procedures,简称 SP),用于从数据库获取数据。请注意,笔者创建了两个存储过程,名字分别为 SelectCitiesWithPaging 与 SelectCitiesWithPagingOldSQLVersions。由于笔者是在 SQL Server 2014 中实现该解决方案的,在第一个 SP 中,笔者使用了 OFFSET FETCH 声明。对于更早的版本,比如 SQL Server 2005 与 SQL Server 2008,则应该使用 ROW_NUMBER() 函数而非 OFFSET FETCH。因此,请创建与开发环境相适合的 SP。与传统的 SP 不同,此处创建的 SP 将包含三个参数,细节如下:
@PageNumber 为将会返回的页码数(Page Number)
@RowsPerPage 为每页的行数(Number of Rows)
@TotalResords(输出参数)为总的记录
-- CREATE DATABASE
CREATE DATABASE TestPagingInASPNET;
GO
-- CREATE FIRST TABLE
CREATE TABLE AdministrativeUnits (
AdministrativeUnitID INT PRIMARY KEY IDENTITY(1, 1),
Name VARCHAR(50)
);
GO
-- CREATE SECOND TABLE
CREATE TABLE Cities (
CityID INT PRIMARY KEY IDENTITY(1, 1),
AdministrativeUnitID INT,
Name VARCHAR(50)
);
GO
-- CREATE THE STORED PROCEDURE
CREATE PROCEDURE SelectCitiesWithPaging
@PageNumber INT,
@RowsPerPage INT,
@TotalRows INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT @TotalRows = COUNT(*)
FROM [AdministrativeUnits] [AU]
INNER JOIN [Cities] [C] ON [AU].[AdministrativeUnitID] = [C].[AdministrativeUnitID]
SELECT [AU].[Name] [Administrative Unit],
[C].[Name] [City]
FROM [AdministrativeUnits] [AU]
INNER JOIN [Cities] [C] ON [AU].[AdministrativeUnitID] = [C].[AdministrativeUnitID]
ORDER BY [AU].[Name], [C].[Name]
OFFSET ((@PageNumber - 1) * @RowsPerPage) ROWS FETCH NEXT @RowsPerPage ROWS ONLY
END
GO
-- CREATE THE STORED PROCEDURE
CREATE PROCEDURE SelectCitiesWithPagingOldSQLVersions
@PageNumber INT,
@RowsPerPage INT,
@TotalRows INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT @TotalRows = COUNT(*)
FROM [AdministrativeUnits] [AU]
INNER JOIN [Cities] [C] ON [AU].[AdministrativeUnitID] = [C].[AdministrativeUnitID]
SELECT *
FROM ( SELECT ROW_NUMBER() OVER (ORDER BY [AU].[Name], [C].[Name]) NUMBER,
[AU].[Name] [Administrative Unit],
[C].[Name] [City]
FROM [AdministrativeUnits] [AU]
INNER JOIN [Cities] [C] ON [AU].[AdministrativeUnitID] = [C].[AdministrativeUnitID]
) tbl
WHERE Number BETWEEN ((@PageNumber - 1) * @RowsPerPage + 1) AND (@PageNumber * @RowsPerPage)
END
GO
现在,讨论应用的前端部分
ASPX
- 在 Web 表单中绘制一个表格,其包含两个表格行(Table Rows)
- 在第一个表格行中推拽下放一个 GridView。此处无需启用分页,因为存储过程实现该功能。
- 在第二个表格行中,放置两个按钮来实现前页与后页之间的跳转。此外,为两个按钮创建点击事件。
- 在第三个表格行中,放置页面导航链接。
- 在下面;提供了 .aspx 文件中的代码。
<table style="width:100%;">
<tr>
<td>
<asp:GridView ID="GridView1" runat="server"></asp:GridView>
</td>
</tr>
<tr>
<td style="text-align:center;">
<asp:Button ID="btnGridViewPrevious" runat="server" OnClick="btnGridViewPrevious_Click" Text="<" />
<asp:TextBox ID="txtGridViewPageNumber" runat="server"></asp:TextBox>
<asp:Button ID="btnGridViewGoToPageNumber" runat="server" Text="Go to Page" OnClick="btnGridViewGoToPageNumber_Click" />
<asp:Button ID="btnGridViewNext" runat="server" OnClick="btnGridViewNext_Click" Text=">" />
</td>
</tr>
<tr>
<td style="text-align:center;" runat="server" id="tdPage">
</td>
</tr>
</table>
ASPX.cs
在 .aspx.cs 文件中,我们会创建两个函数。
GetAndBindData()
- 第一个函数将得到来自数据库的请求数据。请注意,我们以页码数与每页的行数为参数。
- 接收到的数据将填充在网格中。
- 在页面加载(Page Load)事件触发,且参数页面数(PageNumber)为1时,即会调用该函数。
CreatePager()
- 第二个函数将创建用于导航的链接。
private void GetAndBindData(Int32 PageNumber, Int32 RowsPerPage)
{
SqlConnection con = new SqlConnection(ConnectionString);
SqlCommand cmd = new SqlCommand();
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "SelectProjects";
cmd.Connection = con;
SqlParameter par1 = new SqlParameter();
par1.ParameterName = "PageNumber";
par1.DbType = System.Data.DbType.Int32;
par1.Direction = System.Data.ParameterDirection.Input;
par1.Value = PageNumber;
cmd.Parameters.Add(par1);
SqlParameter par2 = new SqlParameter();
par2.ParameterName = "RowsPerPage";
par2.DbType = System.Data.DbType.Int32;
par2.Direction = System.Data.ParameterDirection.Input;
par2.Value = RowsPerPage;
cmd.Parameters.Add(par2);
SqlParameter par3 = new SqlParameter();
par3.ParameterName = "TotalRows";
par3.DbType = System.Data.DbType.Int32;
par3.Direction = System.Data.ParameterDirection.Output;
cmd.Parameters.Add(par3);
SqlDataAdapter adp = new SqlDataAdapter();
adp.SelectCommand = cmd;
DataSet ds = new DataSet();
con.Open();
adp.Fill(ds);
Session["TotalRows"] = par3.Value.ToString();
GridView1.DataSource = ds.Tables[0];
GridView1.DataBind();
}
private void CreatePager(Int32 TotalRecords, Int32 PageNumber, Int32 RowsPerPage)
{
Int32 intIndex;
Int32 intPageNumber;
tdPage.InnerHtml = "";
intPageNumber = 1;
for (intIndex = 1; intIndex <= TotalRecords; intIndex+=10)
{
tdPage.InnerHtml += " <a href=''>" + intPageNumber.ToString() + "</a> ";
intPageNumber++;
}
if (TotalRecords > intIndex) {
tdPage.InnerHtml += " <a href=''>" + intIndex.ToString() + "</a> ";
}
}
protected void btnGridViewNext_Click(object sender, EventArgs e)
{
Int32 NewPageNumber = Convert.ToInt32(Session["PageNumber"]);
NewPageNumber++;
Session["PageNumber"] = NewPageNumber;
txtGridViewPageNumber.Text = Session["PageNumber"].ToString();
GetAndBindData(Convert.ToInt32(Session["PageNumber"]), 10);
btnGridViewPrevious.Enabled = true;
}
protected void btnGridViewGoToPageNumber_Click(object sender, EventArgs e)
{
Int32 NewPageNumber = Convert.ToInt32(txtGridViewPageNumber.Text);
Session["PageNumber"] = NewPageNumber;
txtGridViewPageNumber.Text = Session["PageNumber"].ToString();
GetAndBindData(Convert.ToInt32(Session["PageNumber"]), 10);
btnGridViewPrevious.Enabled = true;
}
要点总结
通过此方法,在用户改变页面索引时,开发者可以只获取相关数据进行展示,而非完整的数据集。这样,不仅可以从数据库中选出相关数据,在 GridView 中过滤数据所需的步骤也可以避免。从而切实提高并优化应用性能。
原文地址:http://www.codeproject.com/Articles/1078662/How-to-implement-Paging-in-ASP-NET-at-SQL-Query-Le
OneAPM 助您轻松锁定 .NET 应用性能瓶颈,通过强大的 Trace 记录逐层分析,直至锁定行级问题代码。以用户角度展示系统响应速度,以地域和浏览器维度统计用户使用情况。想阅读更多技术文章,请访问 OneAPM 官方博客。
本文转自 OneAPM 官方博客
ASP .NET 如何在 SQL 查询层面实现分页的更多相关文章
- MaxCompute如何对SQL查询结果实现分页获取
由于MaxCompute SQL本身不提供类似数据库的select * from table limit x offset y的分页查询逻辑.但是有很多用户希望在一定场景下能够使用获取类似数据库分页的 ...
- 如何在SQL Server查询语句(Select)中检索存储过程(Store Procedure)的结果集?
如何在SQL Server查询语句(Select)中检索存储过程(Store Procedure)的结果集?(2006-12-14 09:25:36) 与这个问题具有相同性质的其他描述还包括:如何 ...
- (25)ASP.NET Core EF查询(复杂查询运算符、原生SQL查询、异步查询)
1.复杂查询运算符 在生产场景中,我们经常用到LINQ运算符进行查询获取数据,现在我们就来了解下生产场景经常出现几种复杂查询运算符. 1.1联接(INNER JOIN) 借助LINQ Join运算符, ...
- 用sql查询当天,一周,一个月的数据
用sql查询当天,一周,一个月的数据 数据查询,不管在网站还是在系统,都很常见,下文是介绍最常见的以日期查询的语句 select * from ShopOrder where datediff(w ...
- 15个初学者必看的基础SQL查询语句
本文由码农网 – 小峰原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 本文将分享15个初学者必看的基础SQL查询语句,都很基础,但是你不一定都会,所以好好看看吧. 1.创建表和数据插 ...
- cache应用(asp.net 2.0 SQL数据缓存依赖 [SqlCacheDependency ] )
Asp.net 2.0 提供了一个新的数据缓存功能,就是利用sql server2005 的异步通知功能来实现缓存 1.首先在sqlserver2005 中创建一个test的数据库. 在SQL Ser ...
- C# EF使用SqlQuery直接操作SQL查询语句或者执行过程
Entity Framework是微软出品的高级ORM框架,大多数.NET开发者对这个ORM框架应该不会陌生.本文主要罗列在.NET(ASP.NET/WINFORM)应用程序开发中使用Entity F ...
- ASP.NET代码调用SQL Server带DateTime类型参数的存储过程抛出异常问题
ASP.NET代码调用SQL Server带DateTime类型参数的存储过程,如果DateTime类型参数的值是'0001/1/1 0:00:00'时,就会抛出异常“Message: SqlDate ...
- 04、SQL 查询当天,本月,本周的记录
SELECT * FROM 表 WHERE CONVERT(Nvarchar, dateandtime, 111) = CONVERT(Nvarchar, GETDATE(), 111) ORDE ...
随机推荐
- 对象属性封装到map中
import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.lang.reflect.Modi ...
- android ListView的介绍和优化
xml设计 <?xml version="1.0"?> -<RelativeLayout tools:context=".MainActivity&qu ...
- UVA 1646 Edge Case
题意:n(3<=n<=10000)个结点组成一个圈,点顺次连接为边,求没有公共点的边集个数. 分析: 1.推规律,n=3有4个,n=4有7个,n=5有11个,n=6有18个,--,a[i] ...
- 【风马一族_xml】xml的基本讲解笔记
xml是如何保存数据的 在xml语言中,它允许用户自定义标签.每个标签用于描述一段数据; 一个标签可以分为开始标签和结束标签,在开始标签和结束标签之间又可以嵌套其它标签,利用标签间的嵌套其它标签,利用 ...
- java基础-注解Annotation原理和用法
在很多java代码中都可以看到诸如@Override.@Deprecated.@SuppressWarnings这样的字符,这些就是注解Annotation.注解最早在jdk5中被引入,现在已经成为j ...
- jQuery插件css3动画模拟confirm弹窗
相比浏览器自带的alert.confirm,能力所及,我更喜欢所有的东西都是自定义:首先在head标签(当然喜欢其他地方自己看着办)内引入插件样式表和js.<link rel="sty ...
- linux前景到底怎么样啊?
我就不长篇大论,举四个例子你看看. 1.目下最热最潮最流行的云计算技术的背后是虚拟化和网格技术,而虚拟化和网格技术基本是Linux的天下,目前虚拟化的三大家:Vmware,Xen,Hyper-V中,市 ...
- How to force to Fullscreen Form
Is it possibile by code resize a form to fullscreen? (like button Maximize) ? // VAR Changed on 10 J ...
- dotNet中初始化器的使用
dotNet中初始化器的使用 2013年12月7日 13:27 有两类初始化器: 对象初始化器和集合初始化器 比如现在有一个User类: Public class User { public in ...
- spring多数据源配置
项目中我们经常会遇到多数据源的问题,尤其是数据同步或定时任务等项目更是如此.多数据源让人最头痛的,不是配置多个数据源,而是如何能灵活动态的切换数据源.例如在一个spring和hibernate的框架的 ...