Returning the SqlDataReader



我正在尝试通过引用传递阅读器或返回一个阅读器。我在退货时遇到了问题。

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());
}

但是我得到以下错误

reader关闭时调用HasRows无效。

任何想法?

这就是问题所在:

finally
{
    conn.Close();
}

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

(不清楚为什么要使用reader变量,因为只在返回时使用它。)

在打开连接的方法中返回SqlDataReader通常是棘手的-因为这意味着你没有一个关闭连接的好方法。更好的做法是让调用者传入连接,此时您可以使用:

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

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

John是对的,为什么你有问题,但你不需要传递一个连接。

我可以看到,你已经使用SqlCommand.ExecuteReader(CommandBehavior)过载,当你启动你的阅读器和传递CommandBehavior. closeconnection。然而,你做错的事情是你从来没有处理过从你的函数返回的读取器。删除finally块,然后将返回的阅读器包装在using块中。这将在退出块时为您关闭底层连接(因为您传入了CommandBehavior.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循环中的代码将永远不会执行。


当出现异常时,仍然需要关闭连接,但是可以将close语句从finally in移到catch语句中。

catch (Exception ex)
{
    conn.Dispose(); //Disposing closes the connection.
    return null;
}

您可以尝试下面的示例http://msdn.microsoft.com/en-us/library/haa3afyz.aspx。

你不应该在使用reader之前调用close方法

Jon Skeet和Scott 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();
    }
}

相关内容

最新更新