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。