【问题标题】:Encapsulating and Disposing SqlClient Objects In Order按顺序封装和释放SqlClient对象
【发布时间】:2019-03-02 16:28:11
【问题描述】:

我正在尝试对我的 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(等)的类来解决这个问题,但是当我用相同的 using 语句包装它时,它占用的行数与数据库连接 using 语句一样多。

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

【问题讨论】:

  • 您要读取什么样的数据?它可以存储在列表或字典中吗?
  • @KevinK。是的,我可以。有时我只返回一件东西,但它可以放在一个列表中。
  • 您应该在关闭连接之前关闭阅读器。所以你应该在收到数据后处理所有的对象。
  • @Eugene:谢谢。这就是我所怀疑的......所以没有办法制作一个可重用的方法来隐藏所有/大部分嵌套的 using 语句?
  • 我会设计解决方案,它会读取里面的所有日期并返回数据集。如果不可能,您可以尝试不同的方法来访问数据。例如 LINQ

标签: c# sql-server dispose idisposable sqlconnection


【解决方案1】:

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

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 语句后,您的一次性对象将始终被释放。

【讨论】:

  • 您已经正确删除了错误的 finally 语句,但没有提到您这样做了,或者为什么?
【解决方案2】:

所以没有办法制作一个可重用的方法来隐藏所有/大部分嵌套的 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

【讨论】:

  • 是的!这是如此修剪和苗条。效果很好。
猜你喜欢
  • 1970-01-01
  • 2012-09-17
  • 1970-01-01
  • 2011-03-24
  • 1970-01-01
  • 2014-07-17
  • 2023-01-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多