首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET 搜尋查詢與分頁完整實作(參數化 SQL + ViewState 狀態管理) ASP.NET 搜尋查詢與分頁完整實作(參數化 SQL + ViewState 狀態管理)

     編輯:ASP.NET 基礎

本文提供一個完整的 ASP.NET Web Forms 搜尋分頁範例,包含前端介面(關鍵字輸入、分頁按鈕)、後端邏輯(參數化 SQL 分頁查詢、總筆數計算、ViewState 管理頁碼狀態),採用 `TOP ... NOT IN` 分頁語法,相容 SQL Server 2000+。

前端頁面


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="分頁.aspx.cs" Inherits="分頁練習.分頁" %>
<html xmlns="https://www.w3.org/1999/xhtml">
<head runat="server">
    <title>搜尋分頁範例</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <table>
                <tr><td>
                    <asp:TextBox ID="txtKey" runat="server" placeholder="輸入關鍵字" />
                    <asp:ImageButton ID="btnQuery" runat="server" OnClick="btnQuery_Click" 
                        ImageUrl="~/images/0.jpg" Width="20" Height="20" />
                    <asp:Label ID="Label1" runat="server" />
                </td></tr>
                <tr><td>
                    <div id="divResult" runat="server"></div>
                </td></tr>
                <tr><td>
                    <asp:LinkButton ID="btnFirst" runat="server" OnClick="btnFirst_Click">第一頁</asp:LinkButton>
                    <asp:LinkButton ID="btnBefore" runat="server" OnClick="btnBefore_Click">上一頁</asp:LinkButton>
                    <asp:LinkButton ID="btnNext" runat="server" OnClick="btnNext_Click">下一頁</asp:LinkButton>
                    <asp:LinkButton ID="btnLast" runat="server" OnClick="btnLast_Click">最後一頁</asp:LinkButton>
                </td></tr>
            </table>
        </div>
    </form>
</body>
</html>

後端程式碼


using System;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace 分頁練習
{
    public partial class 分頁 : Page
    {
        private const int PageSize = 3; // 每頁筆數

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                ViewState["pageindex"] = 1; // 目前頁碼(1-based)
                LoadData();
                CountTotal();
            }
        }

        // 載入當頁資料並渲染 HTML 表格
        private void LoadData()
        {
            string connStr = "Data Source=PC-DLL;Initial Catalog=News;Persist Security Info=True;User Id=sa;Password=linlin";
            int pageIndex = Convert.ToInt32(ViewState["pageindex"]);

            using (SqlConnection conn = new SqlConnection(connStr))
            using (SqlCommand cmd = conn.CreateCommand())
            {
                // 參數化分頁查詢:TOP @PageSize + NOT IN (TOP @Offset)
                cmd.CommandText = @"
                    SELECT TOP (@PageSize) * 
                    FROM T_News 
                    WHERE (NewsTitle LIKE @Key OR NewsContent LIKE @Key)
                      AND Id NOT IN (
                          SELECT TOP ((@PageIndex - 1) * @PageSize) Id 
                          FROM T_News 
                          WHERE NewsTitle LIKE @Key OR NewsContent LIKE @Key 
                          ORDER BY Id
                      )
                    ORDER BY Id";

                cmd.Parameters.AddWithValue("@Key", "%" + txtKey.Text + "%");
                cmd.Parameters.AddWithValue("@PageSize", PageSize);
                cmd.Parameters.AddWithValue("@PageIndex", pageIndex);

                SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                DataTable dt = new DataTable();
                adapter.Fill(dt);

                // 動態產生 HTML 表格
                StringBuilder sb = new StringBuilder();
                sb.Append("<table border='1' cellpadding='5'><tr><th>標題</th><th>內容</th><th>建立時間</th></tr>");
                foreach (DataRow row in dt.Rows)
                {
                    sb.Append("<tr>");
                    sb.Append("<td>" + Server.HtmlEncode(row["NewsTitle"].ToString()) + "</td>");
                    sb.Append("<td>" + Server.HtmlEncode(row["NewsContent"].ToString()) + "</td>");
                    sb.Append("<td>" + row["CreateTime"] + "</td>");
                    sb.Append("</tr>");
                }
                sb.Append("</table>");
                divResult.InnerHtml = sb.ToString();
            }
        }

        // 計算總筆數與總頁數
        private void CountTotal()
        {
            string connStr = "Data Source=PC-DLL;Initial Catalog=News;Persist Security Info=True;User Id=sa;Password=linlin";
            using (SqlConnection conn = new SqlConnection(connStr))
            using (SqlCommand cmd = conn.CreateCommand())
            {
                cmd.CommandText = "SELECT COUNT(*) FROM T_News WHERE NewsTitle LIKE @Key OR NewsContent LIKE @Key";
                cmd.Parameters.AddWithValue("@Key", "%" + txtKey.Text + "%");
                conn.Open();
                int total = Convert.ToInt32(cmd.ExecuteScalar());

                int lastPage = (total % PageSize == 0) ? total / PageSize : total / PageSize + 1;
                ViewState["pagelastindex"] = lastPage; // 總頁數
            }
        }

        // 分頁按鈕事件
        protected void btnFirst_Click(object sender, EventArgs e)
        {
            ViewState["pageindex"] = 1;
            LoadData();
        }

        protected void btnBefore_Click(object sender, EventArgs e)
        {
            int idx = Convert.ToInt32(ViewState["pageindex"]);
            if (idx > 1)
            {
                ViewState["pageindex"] = idx - 1;
                LoadData();
            }
        }

        protected void btnNext_Click(object sender, EventArgs e)
        {
            int idx = Convert.ToInt32(ViewState["pageindex"]);
            int last = Convert.ToInt32(ViewState["pagelastindex"]);
            if (idx < last)
            {
                ViewState["pageindex"] = idx + 1;
                LoadData();
            }
        }

        protected void btnLast_Click(object sender, EventArgs e)
        {
            ViewState["pageindex"] = ViewState["pagelastindex"];
            LoadData();
        }

        protected void btnQuery_Click(object sender, ImageClickEventArgs e)
        {
            ViewState["pageindex"] = 1; // 搜尋重置第一頁
            CountTotal();
            LoadData();
        }
    }
}

關鍵技術點總結

技術點實作細節
參數化查詢所有使用者輸入(`txtKey.Text`)透過 `SqlParameter` 傳入,**完全防止 SQL Injection**
分頁 SQL`SELECT TOP @PageSize ... WHERE Id NOT IN (SELECT TOP ((@PageIndex-1)*@PageSize) ...)`
相容 SQL Server 2000+,無需 `ROW_NUMBER()`
狀態管理`ViewState["pageindex"]` 儲存目前頁碼(1-based),`ViewState["pagelastindex"]` 儲存總頁數
搜尋重置點擊查詢按鈕時,`pageindex` 重設為 1,並重新計算總頁數
HTML 編碼輸出`Server.HtmlEncode()` 防止資料內含 HTML 標籤導致 XSS 或版面錯亂
資源釋放`using` 區塊確保 `SqlConnection`、`SqlCommand`、`SqlDataAdapter` 正確 Dispose

改進建議(生產環境)

  1. 連線字串外部化:移至 `Web.config` ``,勿寫死在程式碼。
  2. 分頁 SQL 效能:大量資料建議改用 `ROW_NUMBER()` 或 `OFFSET/FETCH` (SQL 2012+),避免 `NOT IN` 子查詢效能衰退。
  3. 使用 GridView/Repeater:取代手動 `StringBuilder` 拼接 HTML,支援樣板、排序、編輯等內建功能。
  4. 加入 Try-Catch 與 Log:資料庫操作包裝例外處理,記錄錯誤詳情。
  5. 關鍵字保持:`txtKey.Text` 自動保留於 PostBack(ViewState),分頁時仍帶入查詢條件。

總結

此範例展示了 ASP.NET Web Forms 中**搜尋 + 分頁**的核心實作模式:參數化 SQL 保護安全、`ViewState` 管理分頁狀態、`TOP NOT IN` 相容性分頁語法、手動 HTML 渲染。理解此基礎模式,即可擴充至 GridView、ListView、Repeater 等進階控制項應用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved