使用 SqlDataSource 控件可以很方便的与 UI 控件 (如 GridView、FormView) 系结来呈现数据,若需要针对 SqlDataSource 做数据筛选时,最直觉的方式就是去修改 SqlDataSoruce.SelectCommand 的 SQL 命令来执行数据筛选,这样设定的呈现结果感觉是正确的,数据真得依设定的条件来筛选过滤。可以当 UI 控件重新做 DataBind 时,如 GridView 换页的动作,会发生数据又全部跑出来了。为何会有这样异常的结果呢?本文就是来说明发生这种情形的原因及正确的程序撰写方式。
SqlDataSource 执行数据筛选
在页面上放置 SqlDataSource 及 GridView 来呈现数据,并将 GridView 设定分页,页面控件的配置如下所示,当按下 [Filter] 按钮时,会依选取的字段名称及输入的筛选值来过滤数据。
在 [Filter] 按钮的 Click 事件撰写如下程序代码,主要是依设定的字段及筛选值产生 SQL 语法,并设定给 SqlDataSource.SelectCommand 属性。
Protected
Sub btnFilter_Click()
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
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()
Sub btnDataBind_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDataBind.Click
Response.Write("SelectCommand: " & SqlDataSource1.SelectCommand)
GridView1.DataBind()
End Sub
Response.Write("SelectCommand: " & SqlDataSource1.SelectCommand)
GridView1.DataBind()
End Sub
执行程序,选择 EmployeeID 字段,输入筛选值为 "3",按下 [Filter] 按钮来执行筛选,执行结果可以正确筛选资料。
可是这时我们按下 [DataBind] 按钮,让 GridView 重新做数据系结。这时发生了奇怪的现象,资料怎么全又跑出来了呢?仔细看一下输出的 SqlDataSource.SelectCommand 属性值,它怎么不是我们刚刚设定的筛选 SQL 语法呢?若筛选的数据可以分页,你会发现按换页的结果,也会发生同样的情形,因为 换页也需要 DataBind,所以跟自行去设定 DataBind 的结果是一样的。
为什么设定的 SelectCommand 属性值不见了呢?主要原因就是 SelectCommand 属性并没有被保留在 ViewState 中,所以每次 PostBack 时,它的值就会还原为设计阶段的初始值。
SqlDataSource 执行数据筛选正确作法
即然我们知道原因是「SelectCommand 属性并没有被保留在 ViewState 中」,那最简单的方式就是我们自行撰写程序将其保留在 ViewState 中,故页面覆写 LoadViewState 及 SaveViewState 方法来保留 SelectCommand 属性。
/**/
''' <summary>
''' 由 ViewState 还原控件的状态。
''' </summary>
''' <param name="savedState">要还原的控件状态。</param>
Protected Overrides Sub LoadViewState() 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() 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
''' 由 ViewState 还原控件的状态。
''' </summary>
''' <param name="savedState">要还原的控件状态。</param>
Protected Overrides Sub LoadViewState() 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() 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 属性值也是我们最后设定的值。