SqlClient对象的封装与有序化

Encapsulating and Disposing SqlClient Objects In Order

我正在尝试对我的 Sql 客户端对象调用进行分层,以便可靠地处理它们。像这样:

Open database connection -> Create command -> Read results -> close command -> close database connection

到目前为止,当我用相同的方法完成所有这些事情时,这已经成功了。

问题是这很容易出错。读起来一团糟。

当我尝试创建一个通用方法来处理此问题以清理所有内容时,returns reader 连接在 reader 启动之前关闭。

//closes connection before it can be read...apparently the reader doesn't actually have any data at that point ... relocating to disposable class that closes on dispose
public SqlDataReader RunQuery(SqlCommand command)
{
    SqlDataReader reader = null;
    using (var dbConnection = new SqlConnection(_dbConnectionString))
    {
        try
        {
            dbConnection.Open();

            command.Connection = dbConnection;

            reader = command.ExecuteReader();  // connection closed before data can be read by the calling method
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
        finally
        {
            dbConnection.Close();
        }
    }

    return reader;
}

我可以通过创建自己的 class 实现 IDispose(等)来解决这个问题,但是当我用相同的 using 语句包装它时,它占用的行数与数据库连接 using 语句一样多。

我如何在处理所有这些工件并关闭连接的可重复 class 中处理数据库连接?

您可以创建一个 class 来保存可重复使用的开放数据库连接,但我建议将数据读入列表并返回结果:

public List<object> RunQuery(SqlCommand command)
{
    List<object> results = new List<object>();
    using (var dbConnection = new SqlConnection(_dbConnectionString))
    {
        try
        {
            dbConnection.Open();

            command.Connection = dbConnection;
            using (SqlDataReader reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    // Repeat for however many columns you have
                    results.Add(reader.GetString(0));
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    return results;
}

我不知道你的数据结构,但重要的一点是你需要在处理连接之前读取你的数据(reader.GetString 这样做)。您可以找到有关如何正确读取数据的更多信息 here

编辑:如前所述,我删除了您的 finally 声明。这是因为您的 using 语句本质上是在做同样的事情。您可以将 using 语句视为 try-finally 块。在退出 using 语句后,您的一次性对象将始终被处理。

so there's no way to make a reusable method that tucks away all/most of the nested using statements?

支持从方法返回 DataReader 的特定模式,如下所示:

static IDataReader GetData(string connectionString, string query)
{
    var con = new SqlConnection(connectionString);
    con.Open();
    var cmd = con.CreateCommand();
    cmd.CommandText = query;
    var rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
    return rdr;
}

然后你可以在using块中调用这个方法:

    using (var rdr = GetData(constr, sql))
    {
        while (rdr.Read())
        {
            //process rows
        }
    } // <- the DataReader _and_ the connection will be closed here