当使用sqldatareader如何在三层架构中解决它时,我得到“读取器关闭时调用Read的无效尝试”
当我点击链接按钮时,它给出的错误是“读取器关闭时无效尝试调用读取”我的DAL方法返回dr是
private SqlDataReader getDownload(string sql) { SqlDataReader dr; using (SqlConnection con = ConnectionManager.GetDatabaseConnection()) { SqlCommand cmd = new SqlCommand("getInfo", con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@query", SqlDbType.VarChar).Value = sql; cmd.Connection = con; dr = cmd.ExecuteReader(); } return dr; }
另一种DAL方法是
public SqlDataReader getDownload(int auto_id) { string sql = "select mfile_name,file_data from Viva_Notice where auto_id=" + auto_id; SqlDataReader dr = getDownload(sql) ; return dr; }
我的BLL方法是
public SqlDataReader getDownload(int field) { GetPostAssign mGetPostAssign = new GetPostAssign(); SqlDataReader dr = mGetPostAssign.getDownload(field); return dr; }
当我打电话给它然后得到“读取器关闭时无效尝试呼叫读取”
protected void lnkDownload_Click(object sender, EventArgs e) { try { LinkButton lnkbtn = sender as LinkButton; GridViewRow gvrow = lnkbtn.NamingContainer as GridViewRow; if (gvrow.RowIndex < 0) return; int field = Convert.ToInt32(lnkbtn.Attributes["RowIndex"]); SqlDataReader dr = MclsAssignment.getDownload(field); if (dr.Read()) { Response.AddHeader("Content-Disposition", "attachment;filename=\"" + dr["mfile_name"] + "\""); Response.BinaryWrite((byte[])dr["file_data"]); Response.End(); } } catch (Exception) { throw; } }
这实际上是一个设计问题 – 如果你打算破坏连接,你不能真正返回一个“实时”数据阅读器, SqlDataReader
依赖它,即
SqlDataReader dr; using (SqlConnection con = ConnectionManager.GetDatabaseConnection()) { SqlCommand cmd = new SqlCommand("getInfo", con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@query", SqlDbType.VarChar).Value = sql; cmd.Connection = con; dr = cmd.ExecuteReader(); } // the SqlConnection is disposed here return dr; // dr is now invalid
最重要的是,通过返回SqlDataReader
,您将实现细节泄漏到BLL / UI层。 您应该在连接处于活动状态时读取数据并返回实际数据,以保持良好和干净,例如
public class Download { public string Name { get; set; } public byte[] Data { get; set; } } ... private Download getDownload(string sql) { using (SqlConnection con = ConnectionManager.GetDatabaseConnection()) using (SqlCommand cmd = new SqlCommand("getInfo", con)) { cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@query", SqlDbType.VarChar).Value = sql; con.Open(); Using (SqlDataReader dr = cmd.ExecuteReader()) { while (dr.Read()) { return new Download { Name = (string)dr["mfile_name"], Data = (byte[])dr["file_data"] }; } } } }
这是数据访问层的设计问题。 它并没有像应该那样将应用程序与数据库分离。 它只是与数据库不同的接口而不是使用SQL。 你需要完全解耦它们。 那就是你需要将数据对象返回给应用程序。 然后,应使用阅读器在DAL中填充这些数据对象
所以你的方法是这样的:
private MyFile getDownload(string sql) { SqlDataReader dr; using (SqlConnection con = ConnectionManager.GetDatabaseConnection()) { SqlCommand cmd = new SqlCommand("getInfo", con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@query", SqlDbType.VarChar).Value = sql; cmd.Connection = con; dr = cmd.ExecuteReader(); return new MyFile { file_name = dr["mfile_name], file_data = dr["file_data] } } }
using
语句在最后一个语句在using
块中执行后立即将对象置于上下文中(在本例中为SqlConnection)。 当您在DALfunction之外访问它时,这就是“读取器关闭…”错误的原因。
您应该删除using
块并处理更高层或更好的连接打开/关闭,您应该将SqlDataReader
转换为DAL方法内的对象或DataTable
并返回它。 DataTable示例:
private DataTable getDownload(string sql) { SqlDataReader dr; DataTable dt; using (SqlConnection con = ConnectionManager.GetDatabaseConnection()) { SqlCommand cmd = new SqlCommand("getInfo", con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@query", SqlDbType.VarChar).Value = sql; cmd.Connection = con; dr = cmd.ExecuteReader(); dt = new DataTable(); dt.Load(dr); } return dt; }
你应该改变/添加一个方法
public DataTable getDownload(string sql) { using (SqlConnection con = new SqlConnection(yourconstring)) { SqlDataAdapter dap = new SqlDataAdapter(sql,con); DataTable dt = new DataTable(); dap.Fill(dt); return dt; } }
然后在你的下载点击方法
DataTable dt = MclsAssignment.getDownload(field); if (dt.Rows.Count> 0) { Response.AddHeader("Content-Disposition", "attachment;filename=\"" + (string)dt.Rows[0]["mfile_name"] + "\""); Response.BinaryWrite((byte[])dt.Rows[0]["file_data"]); Response.End(); }