DataReader并没有将数据保存在本地内存中,可以理解成只是指向了数据,连接关闭后用DataReade 读取数据当然无法实现。与DataSet不同,DataSet已经将数据保存在本地内存中。
举例说明
public static SqlDataReader GetDataReader(string sql, params SqlParameter[] parameters) { using (SqlConnection conn = new SqlConnection(connstr)) { SqlCommand cmd = new SqlCommand(sql, conn); foreach (SqlParameter parameter in parameters) { cmd.Parameters.Add(parameter); } try { conn.Open(); SqlDataReader dr = cmd.ExecuteReader(); return dr; } catch (Exception e) { throw new Exception("执行任务失败:" + e.Message + " "+ sql); } } }GetDataReader方法进行封装,调用报错:“阅读器关闭时尝试调用 Read 无效”。这是因为出了using{}的作用域之后,连接自动关闭。
注意:在数据读取完毕之后,不再需要SqlDataReader时,必须将其进行手动关闭。
上述代码解决办法,如下:
SqlConnection对象不在using{}的作用域,手动关闭SqlDataReader对象。
综合案例代码如下:
public SqlDataReader ExecuteReader(string sSQL) { try { SqlConnection conn = new SqlConnection(sConnectionString); using (SqlCommand cmd = new SqlCommand()) { // 绑定有效的数据库连接 cmd.Connection = conn; //再绑定操作的SQL语句 cmd.CommandText = sSQL; cmd.CommandType = CommandType.Text; // 返回值:SqlDataReader类型的记录集 conn.Open(); SqlDataReader sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection); if (sdr.HasRows) { return sdr; } else { return null; } } } catch { return null; } } public SqlDataReader ExecuteReader(CommandType sqlType, string sSQL, SqlParameter[] sqlParameters) { try { SqlConnection conn = new SqlConnection(sConnectionString); using (SqlCommand cmd = new SqlCommand()) { // 绑定有效的数据库连接 cmd.Connection = conn; //判断需要执行的SQL类型,再绑定操作的SQL语句 if (sqlType == CommandType.Text) { cmd.CommandText = sSQL; cmd.CommandType = CommandType.Text; } if (sqlType == CommandType.StoredProcedure) { cmd.CommandText = sSQL; cmd.CommandType = CommandType.StoredProcedure; } //遍历添加到Parameters集合中 foreach (var sqlPara in sqlParameters) { cmd.Parameters.Add(sqlPara); } //上述添加参数parameter可以修改如下 if (sqlParameters!= null) {cmd.Parameters.AddRange(sqlParameters);} // 返回值:SqlDataReader类型的记录集 conn.Open(); //打开数据库的连接 SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection); if (dr.HasRows) { return dr; } else { return null; } } } catch { return null; } }在页面Page_load事件中调用上述代码
protected void Page_Load(object sender, EventArgs e) { SqlHelper sqlHelper = new SqlHelper(); //定义操作的sql语句 string strSQL ="select * from tbClass;Select * from tbBoard"; //获取数据库记录集 SqlDataReader dr = sqlHelper.ExecuteReader(strSQL); //取出记录集 if (dr.HasRows) //记录集是否为空 { do { //高效构造字符串 StringBuilder htmlStr = new StringBuilder(); //表格开始 htmlStr.Append("<table border='1' cellPadding='5' cellSpacing='0' style='font-size:9pt;font:宋体'>"); //表头开始 htmlStr.Append("<tr style='background-color=#f0f0f0'>"); //构造表头 for (int i = 0; i < dr.FieldCount; i++) { //获取指定列的名称 htmlStr.Append(string.Format("<td><strong>{0}</strong></td>", dr.GetName(i))); } //循环向前读取记录,构造表每一行 while(dr.Read()) { //记录行开始 htmlStr.Append("<tr>"); //构造记录行 for (int i = 0; i < dr.FieldCount; i++) { //判断该列是否包含不存在或缺少的值 if (!dr.IsDBNull(i)) htmlStr.Append(string.Format("<td>{0}</td>", dr.GetValue(i))); } //记录行结束 htmlStr.Append("</tr>"); } //表格结束 htmlStr.Append("</table><br>"); Response.Write(htmlStr); } while (dr.NextResult()); //下一个记录集 } dr.Close(); }运行结果,如下:
小结:
传递一个CommandBehavior.CloseConnection参数,则表示将来当用户关闭reader的时候,系统会自动将Connection也关闭掉。即在返回DataReader之前,不要关闭Connection和DataReader。
