Ado.Net: 关闭 SqlCommand 是否会导致关闭 DataReader

Ado.Net: Does closing SqlCommand cause closing DataReader

今天我查看了一些遗留代码,我开始担心了。需要明确关闭 DataReader

我的问题是:关闭 SqlCommand 是否也会关闭关联的 DataReader

这是我的代码:

    using (var conn = new SqlConnection(this.ConnectionString))
    {
        conn.Open();

        using (var cmd = conn.CreateCommand())
        {
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = "House_GetHouseById";

            SqlCommandBuilder.DeriveParameters(cmd);

            cmd.Parameters["@HouseId"].Value = houseId;

            var reader = cmd.ExecuteReader())

            while (reader.Read())
            {

            }
        }
    }

在这段来自 msdn 命令的片段中没有明确关闭:

string queryString =
    "SELECT OrderID, CustomerID FROM dbo.Orders;";

using (SqlConnection connection =
           new SqlConnection(connectionString))
{
    SqlCommand command =
        new SqlCommand(queryString, connection);
    connection.Open();

    SqlDataReader reader = command.ExecuteReader();

    // Call Read before accessing data.
    while (reader.Read())
    {
        Console.WriteLine(String.Format("{0}, {1}",
            reader[0], reader[1]));
    }

    // Call Close when done reading.
    reader.Close();
}

没有。 SqlCommand.Dispose 本质上是一个空操作¹,它不会关闭您的 SqlDataReader

从技术上讲,关闭 SqlConnection 应该会关闭所有资源,有关详细信息,请参阅此问题:

  • Is closing/disposing an SqlDataReader needed if you are already closing the SqlConnection?

但是,这是不好的做法 -- 您依赖于 SqlClient 库的实现细节。 "correct" 方法是处理(通过 Disposeusing)所有 IDisposable 的东西。因此,你的代码应该这样写:

using (var conn = new SqlConnection(this.ConnectionString))
{
    conn.Open();

    using (var cmd = conn.CreateCommand())
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.CommandText = "House_GetHouseById";

        SqlCommandBuilder.DeriveParameters(cmd);

        cmd.Parameters["@HouseId"].Value = houseId;

        using (var reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                // do something
            }
        }
    }
}

¹ 注意,OleDbCommandSqlCeCommand 等其他库的命令 类 并非如此,所以不要养成不配置命令的习惯。

您总是可以将数据读取器包装在 using 指令中,以便在执行超出范围时立即关闭命令,就像 sqlcommand

    using (SqlDataReader reader = cmd.ExecuteReader())
    {
        if (reader != null)
        {
            while (reader.Read())
            {
                //do something
            }
        }
    } // reader is closed here

reader.Close(); //is another way but its too easy to be forgotten.