【编者按】本文作者为来自巴基斯坦的软件开发工程师 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 可以达到同样的效果。

首先进行后端设置:

  1. 创建名为 TestPagingInASPNET 的数据库,
  2. 创建名为 AdministrativeUnits 与 Cities 的两张表。
  3. 创建存储过程(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="&lt;" />
<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="&gt;" />
</td>
</tr>
<tr>
<td style="text-align:center;" runat="server" id="tdPage"> </td>
</tr>
</table>

ASPX.cs

在 .aspx.cs 文件中,我们会创建两个函数。

GetAndBindData()

  1. 第一个函数将得到来自数据库的请求数据。请注意,我们以页码数与每页的行数为参数。
  2. 接收到的数据将填充在网格中。
  3. 在页面加载(Page Load)事件触发,且参数页面数(PageNumber)为1时,即会调用该函数。

CreatePager()

  1. 第二个函数将创建用于导航的链接。
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 查询层面实现分页的更多相关文章

  1. MaxCompute如何对SQL查询结果实现分页获取

    由于MaxCompute SQL本身不提供类似数据库的select * from table limit x offset y的分页查询逻辑.但是有很多用户希望在一定场景下能够使用获取类似数据库分页的 ...

  2. 如何在SQL Server查询语句(Select)中检索存储过程(Store Procedure)的结果集?

    如何在SQL Server查询语句(Select)中检索存储过程(Store Procedure)的结果集?(2006-12-14 09:25:36) 与这个问题具有相同性质的其他描述还包括:如何 ...

  3. (25)ASP.NET Core EF查询(复杂查询运算符、原生SQL查询、异步查询)

    1.复杂查询运算符 在生产场景中,我们经常用到LINQ运算符进行查询获取数据,现在我们就来了解下生产场景经常出现几种复杂查询运算符. 1.1联接(INNER JOIN) 借助LINQ Join运算符, ...

  4. 用sql查询当天,一周,一个月的数据

    用sql查询当天,一周,一个月的数据   数据查询,不管在网站还是在系统,都很常见,下文是介绍最常见的以日期查询的语句 select * from ShopOrder where datediff(w ...

  5. 15个初学者必看的基础SQL查询语句

    本文由码农网 – 小峰原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 本文将分享15个初学者必看的基础SQL查询语句,都很基础,但是你不一定都会,所以好好看看吧. 1.创建表和数据插 ...

  6. cache应用(asp.net 2.0 SQL数据缓存依赖 [SqlCacheDependency ] )

    Asp.net 2.0 提供了一个新的数据缓存功能,就是利用sql server2005 的异步通知功能来实现缓存 1.首先在sqlserver2005 中创建一个test的数据库. 在SQL Ser ...

  7. C# EF使用SqlQuery直接操作SQL查询语句或者执行过程

    Entity Framework是微软出品的高级ORM框架,大多数.NET开发者对这个ORM框架应该不会陌生.本文主要罗列在.NET(ASP.NET/WINFORM)应用程序开发中使用Entity F ...

  8. ASP.NET代码调用SQL Server带DateTime类型参数的存储过程抛出异常问题

    ASP.NET代码调用SQL Server带DateTime类型参数的存储过程,如果DateTime类型参数的值是'0001/1/1 0:00:00'时,就会抛出异常“Message: SqlDate ...

  9. 04、SQL 查询当天,本月,本周的记录

    SELECT * FROM 表 WHERE CONVERT(Nvarchar, dateandtime, 111) = CONVERT(Nvarchar, GETDATE(), 111)   ORDE ...

随机推荐

  1. DBCP--""连接池创建"与"资源关闭"Util类

    import java.io.InputStream; import java.sql.Connection; import java.sql.ResultSet; import java.sql.S ...

  2. Android四大组件之一:Activity

    介绍:活动是最基本的Android组件之一,在应用程序中,一个活动通常就是一个用户界面,每一个活动都被实现为一个独立的类,并且从活动几类中继承, 活动类将会显示由View控件组成的用户接口,并对时间E ...

  3. 在ArcGIS中WGS84大地坐标和投影平面坐标的转换

    以WGS84转换为北京54坐标为例: 首先你要先知道转化的参数,鉴于我国曾使用不同的坐标基准(BJ54.State80.Correct54),各地的重力值又有很大差异,所以很难确定一套适合全国且精度较 ...

  4. Java通过代理类实现数据库DAO操作

    下面的所有代码示例都取自李兴华的<Java Web开发实战经典>的随书源码,因为觉得设计得很好,所以将代码摘录下来作成笔记. 首先,我们在一个java文件中定义要存储的结构类型: impo ...

  5. 【风马一族_Android】Android 前端内容

    Android 前端内容 4.1 View 类概述 4.1.1 关于 View //类型说明 view(视图)指的是用户界面组件的基本构建基块.一个视图占据屏幕上的矩形区域,负责绘图和事件处理.视图是 ...

  6. <邮件服务postfix+mysql>MAIL第二篇

    环境:本服务是建立在第一篇的基础之上的,最好搭建好第一篇 玩此服务的前提是你的系统装好了msql和postfix服务. Postfix+mysql主要是把邮件服务的发与mysql结合使用.当然mysq ...

  7. python 快速入门

    根据以下几个步骤来快速了解一下python,目标是可以利用python来处理一些简易的问题或者写一些工具.   1.编写Hello world 2.学习 if,while,for 的语法 3.学习该语 ...

  8. [大牛翻译系列]Hadoop(7)MapReduce:抽样(Sampling)

    4.3 抽样(Sampling) 用基于MapReduce的程序来处理TB级的数据集,要花费的时间可能是数以小时计.仅仅是优化代码是很难达到良好的效果. 在开发和调试代码的时候,没有必要处理整个数据集 ...

  9. 服务管理,Dll查看

    //枚举系统进程 VOID CManageProcessDlg::ShowProcess() {           m_ListProcess.DeleteAllItems();      HAND ...

  10. KMP算法的理解

    ---恢复内容开始--- 在看数据结构的串的讲解的时候,讲到了KMP算法——一个经典的字符串匹配的算法,具体背景自行百度之,是一个很牛的图灵奖得主和他的学生提出的. 一开始看算法的时候很困惑,但是算法 ...