SqlDataSource 執行資料篩選

SqlDataSource 執行資料篩選

摘要

使用 SqlDataSource 控制項可以很方便的與 UI 控制項 (如 GridView、FormView) 繫結來呈現資料,若需要針對 SqlDataSource 做資料篩選時,最直覺的方式就是去修改 SqlDataSoruce.SelectCommand 的 SQL 命令來執行資料篩選,這樣設定的呈現結果感覺是正確的,資料真得依設定的條件來篩選過濾。可以當 UI 控制項重新做 DataBind 時,如 GridView 換頁的動作,會發生資料又全部跑出來了。為何會有這樣異常的結果呢?本文就是來說明發生這種情形的原因及正確的程式撰寫方式。

SqlDataSource 執行資料篩選

在頁面上放置 SqlDataSource 及 GridView 來呈現資料,並將 GridView 設定分頁,頁面控制項的配置如下所示,當按下 [Filter] 按鈕時,會依選取的欄位名稱及輸入的篩選值來過濾資料。

image

在 [Filter] 按鈕的 Click 事件撰寫如下程式碼,主要是依設定的欄位及篩選值產生 SQL 語法,並設定給  SqlDataSource.SelectCommand 屬性。

 

    Protected Sub btnFilter_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnFilter.Click
        Dim sSQL As String
        Dim sFilter As String

        Select Case ddlFile.SelectedValue.ToUpper
            Case "EmployeeID".ToUpper
                sFilter = "[EmployeeID]=" & txtValue.Text
            Case Else
                sFilter = "[" & ddlFile.SelectedValue & "] Like '%" & txtValue.Text & "%'"
        End Select

        sSQL = "SELECT [EmployeeID], [LastName], [FirstName], [Title], [City] FROM [Employees] Where " & sFilter
        SqlDataSource1.SelectCommand = sSQL
    End Sub

在 [DataBind] 按鈕的 Click 事件撰寫如下程式碼,主要是在顯示 SqlDataSource.SelectCommand 屬性值及執行 GridView.DataBind,使 GridView 重新繫結資料。

    Protected Sub btnDataBind_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDataBind.Click
        Response.Write("SelectCommand: " & SqlDataSource1.SelectCommand)
        GridView1.DataBind()
    End Sub

執行程式,選擇 EmployeeID 欄位,輸入篩選值為 "3",按下 [Filter] 按鈕來執行篩選,執行結果可以正確篩選資料。

image

可是這時我們按下 [DataBind] 按鈕,讓 GridView 重新做資料繫結。這時發生了奇怪的現象,資料怎麼全又跑出來了呢?仔細看一下輸出的 SqlDataSource.SelectCommand 屬性值,它怎麼不是我們剛剛設定的篩選 SQL 語法呢?若篩選的資料可以分頁,你會發現按換頁的結果,也會發生同樣的情形,因為 換頁也需要 DataBind,所以跟自行去設定 DataBind 的結果是一樣的。

image

為什麼設定的 SelectCommand 屬性值不見了呢?主要原因就是 SelectCommand 屬性並沒有被保留在 ViewState 中,所以每次 PostBack 時,它的值就會還原為設計階段的初始值。

 

SqlDataSource 執行資料篩選正確作法

即然我們知道原因是「SelectCommand 屬性並沒有被保留在 ViewState 中」,那最簡單的方式就是我們自行撰寫程式將其保留在 ViewState 中,故頁面覆寫 LoadViewState 及 SaveViewState 方法來保留 SelectCommand 屬性。

 

    ''' <summary>
    ''' 由 ViewState 還原控制項的狀態。
    ''' </summary>
    ''' <param name="savedState">要還原的控制項狀態。</param>
    Protected Overrides Sub LoadViewState(ByVal savedState As Object)
        If Not (savedState Is Nothing) Then
            ' Load State from the array of objects that was saved at ;
            ' SavedViewState.
            Dim myState As Object() = CType(savedState, Object())

            If Not (myState(0) Is Nothing) Then
                MyBase.LoadViewState(myState(0))
            End If

            If Not (myState(1) Is Nothing) Then
                SqlDataSource1.SelectCommand = CType(myState(1), String)
            End If
        End If
    End Sub

    ''' <summary>
    ''' 控制項的狀態儲存至 ViewState。
    ''' </summary>
    ''' <returns>含有控制項之目前檢視狀態的物件。</returns>
    Protected Overrides Function SaveViewState() As Object
        Dim baseState As Object = MyBase.SaveViewState()
        Dim myState(1) As Object
        myState(0) = baseState
        myState(1) = SqlDataSource1.SelectCommand
        Return myState
    End Function

重新執行程式,與之前的做法一樣來篩選資料,最後按下 [DataBind] 按鈕重新做資料繫結,可以發現結果正確了,而輸出的 SelectCommand 屬性值也是我們最後設定的值。

image

ASP.NET 魔法學院