2

我试图通过引用传递给读者或让读者返回。我在退货时遇到了问题。

public static SqlDataReader GetSql(string businessUnit, string taskId)
{
            const string connstring = "Connection string";
            SqlConnection conn = new SqlConnection(connstring);
            SqlCommand command = new SqlCommand();
            SqlDataReader reader;
            try
            {
                conn.Open();
                command.Connection = conn;
                command.CommandType = CommandType.Text;
                command.CommandText =
                    "SELECT * FROM Audits WHERE BusinessUnit = @BU AND TaskID = @TID";
                command.Parameters.AddWithValue("@BU", businessUnit);
                command.Parameters.AddWithValue("@TID", taskId);
                return reader = command.ExecuteReader(CommandBehavior.CloseConnection);
            }
            catch (Exception ex)
            {
                return null;
            }
            finally
            {
                conn.Close();
            }
}


SqlDataReader reader = QaqcsqlLib.GetSql("job", "Task1");

if (reader.HasRows)
{
   while (reader.Read())
      MessageBox.Show(reader[0].ToString());
}

但我收到以下错误

阅读器关闭时调用 HasRows 的尝试无效。

有任何想法吗?

4

4 回答 4

12

这就是问题:

finally
{
    conn.Close();
}

您在方法返回之前关闭连接。如果没有打开的连接,阅读器将无法运行。

(目前还不清楚为什么你有这个reader变量,因为你只在返回时使用它。)

在本身打开连接的方法中返回 aSqlDataReader通常很棘手 - 因为这意味着您没有关闭连接的好方法。最好让调用者通过连接,此时您可以:

using (var connection = new SqlConnection(...))
{
    using (var reader = QaqcsqlLib.GetSql(connection, "job", "Task1"))
    {
        // Use the reader here
    }
}

编辑:正如斯科特所指出的,您的使用CommandBehavior.CloseConnection 允许关闭阅读器以关闭连接。但是,它使其他事情变得更加棘手。例如,如果发生异常,您必须处理连接(因为调用者将没有机会),但否则- 我仍然更喜欢我的方法。

于 2013-05-09T18:18:46.157 回答
4

约翰对您为什么会遇到问题是正确的,但您不需要传递连接。

我可以看到,当您启动阅读器并传入CommandBehavior.CloseConnection时,您已经在使用SqlCommand.ExecuteReader(CommandBehavior)重载。但是,您做错的事情是您永远不会处理从您的函数返回的阅读器。删除块,然后将返回的阅读器包装在一个块中。当您退出块时,这将为您关闭底层连接(因为您传入了)finallyusingCommandBehavior.CloseConnection

using(SqlDataReader reader = QaqcsqlLib.GetSql("job", "Task1"))
{
    while (reader != null && reader.Read()) //Added null check as your GetSql could return null.
      MessageBox.Show(reader[0].ToString());
}

我也剥离了,reader.HasRows因为它是不必要的。如果没有返回结果,则第一次调用reader.Read()将返回 false,并且 while 循环内的代码将永远不会执行。


当发生异常时,您仍然需要关闭连接,但您可以将关闭从 finally 移到 catch。

catch (Exception ex)
{
    conn.Dispose(); //Disposing closes the connection.
    return null;
}
于 2013-05-09T19:01:29.597 回答
0

您可以尝试按照下一个示例 http://msdn.microsoft.com/en-us/library/haa3afyz.aspx进行操作。

在使用阅读器之前,您不应该调用 close 方法。

于 2013-05-09T18:20:20.087 回答
0

Jon SkeetScott Chamberlain都是正确的。如果您希望保持构建代码的方式(与 Jon Skeet 的方法相反),则需要修改代码,以便在执行 SqlCommand 时发生错误时关闭连接。

public static SqlDataReader GetSql(string businessUnit, string taskId)
{
    const string connstring = "Connection string";
    SqlConnection conn = null;
    SqlCommand command = null;
    SqlDataReader reader = null;
    try
    {
        conn = new SqlConnection(connstring);
        command = new SqlCommand();
        command.Connection = conn;
        command.CommandType = CommandType.Text;
        command.CommandText = "SELECT * FROM Audits WHERE BusinessUnit = @BU AND TaskID = @TID";
        command.Parameters.AddWithValue("@BU", businessUnit);
        command.Parameters.AddWithValue("@TID", taskId);
        conn.Open();
        reader = command.ExecuteReader(CommandBehavior.CloseConnection);
        conn = null;
        return reader;
    }
    catch (Exception ex)
    {
        return null;
    }
    finally
    {
        if (conn != null) conn.Dispose();
        if (command != null) command.Dispose();
    }
}
于 2013-05-09T21:29:49.860 回答