ASP .NET 如何在 SQL 查詢層面實現分頁

【編者按】本文做者爲來自巴基斯坦的軟件開發工程師 Aqeeel,主要介紹了在 SQL 查詢層面實現 ASP.NET 應用的分頁方法。html

本文系 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 的兩張表。spa

  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/1078...

OneAPM 助您輕鬆鎖定 .NET 應用性能瓶頸,經過強大的 Trace 記錄逐層分析,直至鎖定行級問題代碼。以用戶角度展現系統響應速度,以地域和瀏覽器維度統計用戶使用狀況。想閱讀更多技術文章,請訪問 OneAPM 官方博客
本文轉自 OneAPM 官方博客

相關文章
相關標籤/搜索