按顺序封装和分配SqlClient对象

时间:2018-09-26 20:14:10

标签: c# sql-server dispose idisposable sqlconnection

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

  

打开数据库连接->创建命令->读取结果->关闭   命令->关闭数据库连接

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

问题是这容易出错。还有一堆通读。

当我尝试创建一个通用方法来清理所有内容并返回读取器时,连接将在读取器启动之前关闭。

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

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

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

2 个答案:

答案 0 :(得分:3)

您可以创建一个包含可重用的开放数据库连接的类,但是我建议将数据读入列表并返回结果:

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语句后,将始终丢弃您的可丢弃对象。

答案 1 :(得分:1)

  

因此,没有办法使可重复使用的方法删除所有/大部分嵌套的using语句吗?

有一种支持从方法返回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