0

当我单击链接按钮时,它给出的错误是“阅读器关闭时调用读取的尝试无效”我返回 dr 的 DAL 方法是

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;
}
}
4

4 回答 4

7

这确实是一个设计问题-如果您打算破坏连接,则无法真正返回“实时”数据读取器,这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. 您应该在连接处于活动状态时读取数据并返回实际数据以保持良好和干净,例如

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"]
                };
            }
        }
    }
}
于 2013-08-12T10:34:28.547 回答
1

这是您的数据访问层的设计问题。它没有像预期的那样将应用程序与数据库分离。它只是与使用 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]
        }
    }
}
于 2013-08-12T10:43:12.883 回答
0

你应该改变/添加一个方法

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();
        }
于 2013-08-12T10:44:50.843 回答
0

using语句在块中的最后一条语句执行后立即将对象置于上下文中(在本例中为 SqlConnection)using。这就是您在 DAL 函数之外访问它时收到错误“阅读器已关闭...”的原因。

您应该删除using块并在更高层处理连接打开/关闭,或者更好的是,您应该转换SqlDataReader为对象或DataTable在 DAL 方法内部并返回它。数据表示例:

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;
}
于 2013-08-12T10:38:50.977 回答