【編者按】本文作者爲來自巴基斯坦的軟件開發工程師 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 DATABASECREATE DATABASE TestPagingInASPNET;GO-- CREATE FIRST TABLECREATE TABLE AdministrativeUnits ( AdministrativeUnitID INT PRIMARY KEY IDENTITY(1, 1), Name VARCHAR(50));GO-- CREATE SECOND TABLECREATE TABLE Cities ( CityID INT PRIMARY KEY IDENTITY(1, 1), AdministrativeUnitID INT, Name VARCHAR(50));GO-- CREATE THE STORED PROCEDURECREATE PROCEDURE SelectCitiesWithPaging @PageNumber INT, @RowsPerPage INT, @TotalRows INT OUTPUTASBEGIN 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 ONLYENDGO-- CREATE THE STORED PROCEDURECREATE PROCEDURE SelectCitiesWithPagingOldSQLVersions @PageNumber INT, @RowsPerPage INT, @TotalRows INT OUTPUTASBEGIN 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)ENDGO
現在,討論應用的前端部分
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 官方博客
+