项目要求比较简单,可做的时候发现,并没有想像中的那样顺手,在一些细节上还是费了不少功夫,所以有必要记录一下。
1. OleDb的参数构造
数据库是access,连接使用传统的.OleDb。OleDbCommand对象,不支持命名参数,一律用问号占位,给它的参数赋值的时候,一定要对应问号的顺序的,当然,也可以给参数命名,不过没什么用,这里只认顺序。可以用循环的方式创建Parameters,注意的是这里OleDbParameter()是一个没有任何参数的构造,当然也可以使用更复杂的构造,但这里没有参数名称,所以就用最简单的构造了。
OleDbParameter (String, OleDbType) | |
OleDbParameter (String, OleDbType, Int32) |
cmd = new OleDbCommand(cmdStr, conn);
for (int i = 0; i < 4; i++)
{
cmd.Parameters.Add(new OleDbParameter());
}
cmd.Parameters[0].Value = txtTopic.Text;
cmd.Parameters[1].Value = txtOrigin.Text;
cmd.Parameters[2].Value = fbContent.Text;
cmd.Parameters[3].Value = this.CatalogID;
2.奇怪的“like”
以前做asp项目的时候,也用access数据库,从来没有觉得模糊查询有什么问题。
用OleDbCommand对象操作查询,用参数的方式(注意%前后的单引号),没有问题
cmdStr = "select count(newsid) from [news] where and newstopic like '%'+ ? + '%'";
cmd = new OleDbCommand(cmdStr, conn);
cmd.Parameters.Add(new OleDbParameter());
cmd.Parameters[0].Value = Keyword;
传统的变量拼接查询字符串(单引号和上面不太一样),也ok
cmdStr = "select count(newsid) from [news] where and newstopic like '%"+ Keyword + "%'";
cmd = new OleDbCommand(cmdStr, conn);
不用参数,不用变量,直接写,查不到!
cmdStr = "select count(newsid) from [news] where and newstopic like '%新闻%'";
cmd = new OleDbCommand(cmdStr, conn);
直接在access2003建一个查询,输入
select count(newsid) from [news] where and newstopic like '%新闻%'
还是查不到
%换成*,access中可以查出正确的结果
select count(newsid) from [news] where and newstopic like '*新闻*'
但为了考虑程序的兼容性,我没有试验*的效果。究竟是为什么上面的问题,查了一些资料也没有清楚的解释。建议用第一种参数传入的方式,这样可以避免注入,比较保险。
3.页面中的持久量。
所谓持久量,主要是一些在页面生存周期中,一直存在并且值固定的量。最常用的一个例子是,页面获取从url传来的参数,如ID号。最早我是使用static变量来保存这个值,在page_load()中给它赋值,值就一直保存在内存中。这是最简单的方法,但在并发时有一定风险。后来改用viewstate来保存,可能我比较懒,觉得每次都用viewstate["XXX"]这样方式,很多时候还需要判定是否为null,还有一些类型转换,用起来比较麻烦。我想,是否可以定义一个只读属性来存储这个量,试验了一下还不错,这样也符合面向对象的思想。
public int CatalogID
{
get
{
if (Request.QueryString["id"] != null)
return Int16.Parse(Request.QueryString["id"]);
else
return -1;
}
}
这样页面中任意位置都可以调用CatalogID 了。
4.Repeater 中的OnItemCommand事件
我在Repeater中放置了几个按钮,也注册了OnItemCommand事件,可点击按钮以后却没有达到预期的效果,设置断点,发现点击按钮的时候根本没有进入处理事件的方法,百思不得其解。在论坛上查了一下,终于找到解决方法,page_load()方法里,如果控件被绑定之前没有判定IsPostBack,注册的OnItemCommand就不起作用。引用网上的一段资料
------“注意如果我们每次在页面装载时均将数据绑定至DataGrid(也就是说我们省略了If Not Page.IsPostBack检查),detailsClicked事件处理程序将不会执行,因为重新绑定DataGrid将会清空(flush out)ItemCommand事件。(请重新阅读上面的两段文字-根据各位对DataGrid的了解,你们很有可能忘记执行回发检查并导致DataGrid不能触发针对按钮的事件处理代码。相信我,这件事在我身上多次发生!J)
”
总之page_load()中,重新绑定数据,控件上的事件就没有了!
2.0中的masterpage是一个好用的东东,但是要注意合并后页面执行事件的先后顺序
- 母版页控件 Init 事件。
- 内容控件 Init 事件。
- 母版页 Init 事件。
- 内容页 Init 事件。
- 内容页 Load 事件。
- 母版页 Load 事件。
- 内容控件 Load 事件。
- 内容页 PreRender 事件。
- 母版页 PreRender 事件。
- 母版页控件 PreRender 事件。
- 内容控件 PreRender 事件。
母板页中的控件ID,到了客户端以后也有变化,比如母板页上的按钮id为bnPost,到客户端成了ct100_$bnPost,
这个客户端id可以用ClientID属性来找,需要在客户端做数据验证的时候一定要注意。当然这里用验证控件不会有问题,但我还是比较喜欢自己写客户端验证。
6.ClientScriptManager.RegisterClientScriptBlock 方法
以前1.1有page.RegisterClientScriptBlock 方法来包装脚本,但2.0中已经过时,统一用ClientScriptManager来处理脚本。
public void RegisterClientScriptBlock (
Type type,
string key,
string script,
bool addScriptTags
)第一个参数,我也没搞太清楚,反正用的时候一律this.GetType()就搞定,第二三个参数和以前一样没什么好说的,RegisterClientScriptBlock其中一个重载方法,就只包括了这三个参数,为什么我要列出4个参数的方法呢,addScriptTags如果为true,就会自动加上<scirpt language="javascript"></script>标记了,是不是很方便呢?