博客上线了这么久,一直还是用的Access数据库,不过程序是采用了工厂模式,预定义好了业务接口,方便以后移植到其它数据库上来,不过以前还是使用sqlserver数据库多一点,这次使用Access数据库还是会碰到一些小问题,总体用起来还是很方便,每次备份数据库就直接从ftp上拉下来就是,感觉性能还行,不过这些可能都是建立在小数据量下。
Q1:Access连接字符怎么写?
A1:Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|blog.mdb。
说明:从.Net2.0开始MS开始有App_Data目录来专门存放数据文件,而对于连接字符串数据库的文件位置可以使用DataDirectory关键来表示它的物理路径,从而在获取连接字符串的时候不再需要使用Server.MapPath()转换。
Q2:时间类型的字段如何处理?
A2:使用Convert.ToDateTime()进行显示的转换一次即可。
说明:Access数据库的时间类型字段需要进行特殊的处理,不然会报错。对于使用OleDbParameter传递参数的时候应该这样来写:
先把PostDate的日期类型ToString()再Convert成DateTime类型。 而对于使用sql语句的日期类型需要使用#来包括日期,不能使用单引号,正确的写法如下:parms.Add(new OleDbParameter("postDate", Convert.ToDateTime(article.PostDate.ToString())));
这样组装的sql语句才不会出错。如果使用参数化查询,也需要先把参数值使用Convert.ToDateTime( postDate.ToString())进行转换,否则可能会报标准表达式中数据类型不匹配的错误。string cmdText = string.Format("SELECT * FROM BL_Article WHERE [postDate] <= #{0}#", Convert.ToDateTime(article.PostDate.ToString()));
Q3:如何返回新插入记录的自动增长编号?
A3:这里我自己写了一个方法专门用来返回新插入记录的自动增长编号,同时适用于sqlserver数据库。
/// <summary>
/// 插入一条新记录,并返回当前自动增长编号
/// </summary>
/// <param name="sql">Insert语句</param>
/// <param name="parms">参数</param>
/// <returns>当前插入记录的自动增长编号</returns>
public static int ExecuteNonQueryReturnIdentity(string sql, List<OleDbParameter> parms)
{
OleDbConnection conn = new OleDbConnection(CONN_STRING);
OleDbCommand cmd = new OleDbCommand(sql, conn);
if (parms != null && parms.Count > 0)
{
//添加参数
foreach (OleDbParameter parameter in parms)
{
cmd.Parameters.Add(parameter);
}
}
int record = 0;
OleDbTransaction tr = null;
conn.Open();
tr = conn.BeginTransaction();
cmd.Transaction = tr;
record = cmd.ExecuteNonQuery();
if (record > 0)
{
cmd.CommandText = "SELECT @@identity";
record = int.Parse(cmd.ExecuteScalar().ToString());
}
tr.Commit();
conn.Close();
return record;
}
说明:先添加参数,然后开始事务,接着正常的ExecuteNonQuery()执行Insert语句,接下来注意使用了Command来ExecuteScalar了SELECT @@identity语句,这样就是用的同一个连接会话,返回第一行第一列identity即是新插入记录的自动增长编号。
Q4:Access如何按yyyy-MM-dd时间格式查询每天的归档?
A4:sql语句如下:
select cstr(DatePart('yyyy',postDate)) '-' cstr(DatePart('m',postDate)) '-' cstr(DatePart('d',postDate)) as [date],count(articleId) as [count] from BL_Article group by cstr(DatePart('yyyy',postDate)) '-' cstr(DatePart('m',postDate)) '-' cstr(DatePart('d',postDate))
说明:使用DataPart来取日期的部分值,然后使用cstr转换成字符串类型,使用 号连接起来,最后使用group by进行分组,如果是需要按月进行归档统计去掉DataPart('d',postDate)的部分就有了。
Q5:Access数据库还有其他的注意项吗?
A5:Access是一个轻量级的桌面数据库,当然它的功能语法上和其他数据库比还是有一定的限制的。
说明:只支持单条语句的执行,不能使用一些高级的语法,分页比较麻烦。不能使用!=号,但可以使用<>代替。关键字的问题,有时候列使用了title、password一些关键字会报一些莫名奇妙的错误,让人摸不着头脑,使用[]来包括列即可解决问题,当然其它数据库也会存在这个问题,养成把所有列都用[]包括起来的良好习惯才是。以后如果遇到一些使用Access数据库的问题将继续更新。
Q6:至少一个参数没有被指定值。
A6:使用Asp.Net执行修改操作报至少一个参数没有被指定值的错。
说明:看起来好象是在sql语句里使用了参数化查询,但执行的时候没有传递参数进去,但我一个个字段对照发现每个参数有值传递,纳闷了好久。跑到数据库那里去看,原来一个字段名称错了还没有修改过来,其实就是指定的一个列名不存在,但报至少一个参数没有被指定值这样的错误提示信息实乃误导。
Q7:语法错误 (操作符丢失) 在查询表达式 'INNER JOIN...'中。
A7:这样是在Access数据库中使用INNER JOIN语法的问题。
说明:Access能使用INNER JOIN语法,但是和其他数据库不同是多个INNER JOIN需要使用()包括起来,如果只关联一个表用INNER JOIN不需要,如select * from a inner join b on a.id = b.id,但是多个INNER JOIN使用就必须把前一个INNER JOIN用()包括起来,如select * from (a inner join b on a.id = b.id) inner join c on a.cid = c.cid,否则将报如上语法错误。