[习题]给初学者的范例,多重字段搜寻引擎 for GridView
http://www.dotblogs.com.tw/mis2000lab/archive/2008/04/25/3503.aspx
[习题]给初学者的范例,多重字段搜寻引擎 for GridView #2,兼论 SqlDataSource与SelectParameter的用法
http://www.dotblogs.com.tw/mis2000lab/archive/2008/04/25/3505.aspx
==========================================================
关于搜寻引擎的作法,我以前在 ASP.NET1.X版 就有提过,概念完全相同。
同时要搜寻多个字段,是有一点小诀窍的~
比较大的差异,是因为ASP.NET2.0新增的 SqlDataSource是一个精简版的数据存取功能,虽然比传统 ADO.NET更简便好用,但很多执行细节,也因为精灵带着我们一步一步走,而让初学者有点迷惘,甚至遇见问题无法修改。
我们用执行的图片,来介绍一下会出现哪种Bug ??
图片说明:多重字段的搜寻引擎,一旦搭配GridView「分页」功能,就出问题啦~
以下是我测试的一点小心得:
1. 首先,在Visual Studio 2005/2008开发工具里面,把 GridView拉进来,简单的设定一下。完成之后,把SqlDataSource卷标里面的 「SQL指令」删除,这部份要放在后置程序代码,要自己手动撰写。
只留下这样子
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:testConnectionString%>">
</asp:SqlDataSource>
2. 多字段的搜寻引擎,搭配的SQL指令,必须是以「字符串」合并的方式来呈现,这样才能找得精准。这种作法很常见,网络上讨论大概都是这样作的,但市面上的书都不讲。
IF 字段一的值,「不是」空白 Then
mySQLStr = " AND 字段一 like '%" & 字段一的值 &"%'"
End IF
IF 字段二的值,「不是」空白 Then
mySQLStr = " AND 字段二 like '%" & 字段二的值 &"%'"
End IF '----批注:以此类推。
SqlDataSource1.SelectCommand = "SELECT * FROM 资料表 WHERE 1=1 " + mySQLStr
请找一下我的旧文章----「进阶的搜寻引擎」,就是讲这一部份的程序,不难!
A.简单的搜寻引擎(单一字段搜寻)
B.进阶的搜寻引擎(多重字段搜寻)
2010/3/5补充 -- 黑暗执行绪的文章 , http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/03/02/or-operator-in-sql.aspx
3. 上面都很简单。不过,一使用 GridView的「分页」功能,就会出问题。
解决的方法,就是SQL指令的部份,必须自己手动撰写。而且要很清楚这些SQL指令该放在「后置程序代码」的哪些地方......
作法满简单的,但初学者只会使用现成的控件来工作、只会用精灵来完成.....遇见状况就不知道该如何下手解决了。
这个问题,是让初学者必须开始「思考」ASP.NET背后是怎么运作的! ..........
请继续看下去:
为了解决这个问题,所以程序改写如下:
兼论 SqlDataSource与SelectParameter的用法
HTML画面
================================================================================
Title: <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<br />
Summary: <asp:TextBox ID="TextBox2"runat="server"></asp:TextBox><br />
Article: <asp:TextBox ID="TextBox3"runat="server"></asp:TextBox>
<asp:ButtonID="Button1" runat="server" Text="Search~" /><br/>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"CellPadding="4"
DataKeyNames="id" Font-Size="X-Small" ForeColor="#333333"AllowPaging="True" PageSize="3"
DataSourceID="SqlDataSource1">
<FooterStyle BackColor="#1C5E55" Font-Bold="True" ForeColor="White"/>
<Columns>
<asp:BoundField DataField="id" HeaderText="id" InsertVisible="False"ReadOnly="True" SortExpression="id" />
<asp:BoundField DataField="test_time" HeaderText="test_time"SortExpression="test_time" DataFormatString="{0:yyyy/MM/dd}"HtmlEncode="False" />
<asp:BoundField DataField="title" HeaderText="title" SortExpression="title">
<ItemStyle Font-Bold="True" Font-Size="Medium" ForeColor="#004000"/>
</asp:BoundField>
<asp:BoundField DataField="summary" HeaderText="summary"SortExpression="summary" />
<asp:BoundField DataField="article" HeaderText="article"SortExpression="article" >
<ItemStyle Font-Size="X-Small" ForeColor="Purple" />
</asp:BoundField>
<asp:BoundField DataField="author" HeaderText="author" SortExpression="author"/>
</Columns>
<RowStyle BackColor="#E3EAEB" />
<EditRowStyle BackColor="#7C6F57" />
<SelectedRowStyle BackColor="#C5BBAF" Font-Bold="True" ForeColor="#333333"/>
<PagerStyle BackColor="#666666" ForeColor="White" HorizontalAlign="Left"/>
<HeaderStyle BackColor="#1C5E55" Font-Bold="True" ForeColor="White"/>
<AlternatingRowStyle BackColor="White" />
<EmptyDataTemplate>
<strong><span style="font-size: 16pt; color: #ff0000">Sorry!!....NOTHING!!</span></strong>
</EmptyDataTemplate>
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1"runat="server"
ConnectionString="<%$ ConnectionStrings:testConnectionString%>">
批注: SqlDataSource里面是空的!!
</asp:SqlDataSource>
以下是后置程序代码,
本文提供VB / C#两种版本给大家参考:
================================================================================
Code-Behind (for VB)
================================================================================
因为上方的HTML码里面,已经有一个「空的」 SqlDataSource,
里面也有数据库联机字符串了,所以底下的 DBInit()只需要拼凑、「组合」出适当的 SQL指令即可。
01 Sub myDBInit() myDBInit()
02 '== SqlDataSource精灵 自动产生的SQL指令,可以当作参考 ==
03 'SqlDataSource1.SelectCommand = "SELECT * FROM [test] WHERE (([title]LIKE '%' + @title + '%') AND ([summary] LIKE '%' + @summary + '%') AND ([article]LIKE '%' + @article + '%'))"
04
05 SqlDataSource1.SelectParameters.Clear()
06
07 '==以下是自己改写的「多重字段 搜寻引擎」,SQL指令的文字组合 ==
08 Dim mySQLstr As String = " 1=1 "
09
10 If TextBox1.Text <> ""Then
11 mySQLstr= mySQLstr + " AND ([title] LIKE '%' +@title + '%')"
12 '== 重点在此:参数必须写在IF判别式这里,不能一起写在后面。==
13 '== 否则,写在下面那区,所有出现的参数,不能留白! ==
14 SqlDataSource1.SelectParameters.Add("title", TextBox1.Text)
15 End If
16 If TextBox2.Text <> ""Then
17 mySQLstr= mySQLstr + " AND ([summary] LIKE '%'+ @summary + '%')"
18 SqlDataSource1.SelectParameters.Add("summary", TextBox2.Text)
19 End If
20 If TextBox3.Text <> ""Then
21 mySQLstr= mySQLstr + " AND ([article] LIKE '%'+ @article + '%')"
22 SqlDataSource1.SelectParameters.Add("article", TextBox3.Text)
23 End If
24
25 '============================================
26 '== 连结数据库的连接字符串 ConnectionString ==
27 'SqlDataSource1.ConnectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings("testConnectionString").ConnectionString
28 '== 撰写SQL指令 ==
29 SqlDataSource1.SelectCommand= "SELECT * FROM [test] WHERE" + mySQLstr
30
31 Response.Write("<hr>您要搜寻哪些字段?SQL指令为 " & SqlDataSource1.SelectCommand& "<hr>")
32 '== 重点在此:参数必须写在上面的「每一个IF判别式」里面,不能一起写在这边。==
33 '== 否则,这里有出现的参数,就必须有「值」,不能留白! ==
34 'SqlDataSource1.SelectParameters.Add("title", TextBox1.Text)
35 'SqlDataSource1.SelectParameters.Add("summary", TextBox2.Text)
36 'SqlDataSource1.SelectParameters.Add("article", TextBox3.Text)
37
38 '== 执行SQL指令 .select() ==
39 'Dim dv As Data.DataView = SqlDataSource1.Select(New DataSourceSelectArguments)
40
41 'GridView1.DataSource = dv
42 'GridView1.DataBind()
43 '============================================
44 End Sub
45
46 Protected Sub Button1_Click() Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
47 If GridView1.PageIndex <>0 Then
48 '==如果不加上这行IF判别式,当我们看第四页时,
49 '==又输入新的条件,重新作搜寻。「新的」搜寻结果将会直接看见第四页!===
50 GridView1.PageIndex= 0
51 End If
52 myDBInit()
53 End Sub
54
55 Protected Sub GridView1_PageIndexChanging() Sub GridView1_PageIndexChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewPageEventArgs)Handles GridView1.PageIndexChanging
56 GridView1.PageIndex = e.NewPageIndex
57
58 Response.Write("目前位于第" & CInt(e.NewPageIndex.ToString()) + 1& "页<br>")
59 '== 必须把 GridView1 的 [EnableSortingAndPagingCallBack]属性关闭(=False),才会执行到这一行! ==
60 End Sub
61
62 Protected Sub GridView1_PageIndexChanged() Sub GridView1_PageIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles GridView1.PageIndexChanged
63 myDBInit()
64 End Sub
================================================================================
Code-Behind (for C#)
================================================================================
因为上方的HTML码里面,已经有一个「空的」 SqlDataSource,
里面也有数据库联机字符串了,所以底下的 DBInit()只需要拼凑、「组合」出适当的 SQL指令即可。
01 protected void DBInit()
02 ...{
03 //== SqlDataSource精灵 自动产生的SQL指令,可以当作参考 ==
04 SqlDataSource1.SelectParameters.Clear();
05
06 //==以下是自己改写的「多重字段 搜寻引擎」,SQL指令的文字组合 ==
07 string mySQLstr = " 1=1 "; //请注意, 1=1后面多一个空白!
08
09 if (TextBox1.Text != "")
10 ...{
11 mySQLstr= mySQLstr + " AND ([title] LIKE '%' +@title + '%')";
12 //== 重点在此:参数必须写在IF判别式这里,不能一起写在后面。==
13 SqlDataSource1.SelectParameters.Add("title", TextBox1.Text);
14 }
15
16 if (TextBox2.Text != "")
17 ...{
18 mySQLstr= mySQLstr + " AND ([summary] LIKE '%'+ @summary + '%')";
19 SqlDataSource1.SelectParameters.Add("summary", TextBox2.Text);
20 }
21
22 if (TextBox3.Text != "")
23 ...{
24 mySQLstr= mySQLstr + " AND ([article] LIKE '%'+ @article + '%')";
25 SqlDataSource1.SelectParameters.Add("article", TextBox3.Text);
26 }
27
28 //============================================
29 //== SqlDataSource1 数据库的连接字符串 ConnectionString,
30 //== 已事先写在「HTML画面的设定」里面 ==
31 //============================================
32
33 //== 最后,合并成完整的SQL指令(搜寻引擎~专用) ==
34 SqlDataSource1.SelectCommand= "SELECT * FROM [test] WHERE" + mySQLstr;
35
36 //==================================================
37 //== 执行SQL指令 与 GridView1.DataBind()的部份,均已经事先写好
38 //==在「HTML画面的设定」上,也就是下面这一行,就通通搞定了。ASP.NET 真强!
39 //==<asp:GridView ID="GridView1" DataSourceID="SqlDataSource1">
40 //==================================================
41
42 Response.Write("<hr>您要搜寻哪些字段?SQL指令为 " + SqlDataSource1.SelectCommand+ "<hr>");
43 //== 重点在此:参数必须写在上面的「每一个IF判别式」里面,不能一起写在这边。==
44 //== 否则,这里有出现的参数,就必须有「值」,不能留白! ==
45 //SqlDataSource1.SelectParameters.Add("title", TextBox1.Text);
46 //SqlDataSource1.SelectParameters.Add("summary", TextBox2.Text);
47 //SqlDataSource1.SelectParameters.Add("article", TextBox3.Text);
48
49 //== 执行SQL指令 .select() ==
50 //DataView dv = SqlDataSource1.Select(new DataSourceSelectArguments);
51
52 //GridView1.DataSource = dv;
53 //GridView1.DataBind();
54 //============================================
55 }
56
57 protected void Button1_Click(object sender, EventArgs e)
58 ...{
59 if (Convert.ToInt32(GridView1.PageIndex)!= 0)
60 ...{
61 //==如果不加上这行IF判别式,假设当我们看第四页时,
62 //==又输入新的条件,重新作搜寻。「新的」搜寻结果将会直接看见 "第四页"!这个问题发生在这里,请看!===
63 GridView1.PageIndex= 0;
64 }
65
66 DBInit();
67 }
68
69 protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgse)
70 ...{
71 GridView1.PageIndex= e.NewPageIndex;
72
73 Response.Write("目前位于第" + (Convert.ToInt32(e.NewPageIndex)+ 1) + "页<br>");
74 //== 把 GridView1 的 [EnableSortingAndPagingCallBack]属性关闭(=False),才会执行到这一行! ==
75 }
76
77 protected void GridView1_PageIndexChanged(object sender, EventArgs e)
78 ...{
79 DBInit();
80 }
2010/6/7补充,关于这个搜寻引擎的范例(GridView ,共有两篇文章),
我撰写一篇完整的文章与您分享,请看:
[文章下载]网站内的搜寻引擎,单一字段与多重字段的搜寻(自己手写SqlDataSource与SelectParameter参数)
上面的程序代码,可能遭受数据隐码(SQLInjection)的攻击,请各位小心。
关于SQLInjection的介绍与解法,可以参考黄忠成老师的大作:
LINQ - 对付 SQL Injection的 "免费补洞策略"
一 连串的 Mass SQL Injection 攻击,让我们回忆起数年前的 SQL Injection 攻击,多年后的今天,我们仍深陷于同样的危机中,本文详述 SQL Injection 的历史、肇因、解决及侦测方法,更为读者们引介全新、更加安全的防堵 SQL Injection 策略。
....................................................................................................寄信给我 mis2000lab (at)雅虎.com.台湾 ........
ASP.NET案例精编(清华大学出版社 / 作者MIS2000Lab)
http://www.china-pub.com/46063
2009/5/15上市
市场价 :¥59.80 RMB(人民幣)