【问题标题】:How to solve the "Connection Was Not Closed, The connections current state is open" in c#?如何解决 C# 中的“连接未关闭,连接当前状态为打开”?
【发布时间】:2023-01-20 20:34:18
【问题描述】:

所以我正在尝试练习 c# 并偶然发现连接错误,我已经声明我的连接将关闭但它告诉我我的连接仍然打开。我真的不知道这有什么问题。

public void getdept()
{
   con.Open();

   string query = "SELECT * FROM positions where PositionName=" + cbxposname.SelectedValue.ToString() + "";

   SqlCommand cmd = new SqlCommand(query, con);

   DataTable dt = new DataTable();

   SqlDataAdapter sda = new SqlDataAdapter(query, con);

   sda.Fill(dt);
       
   foreach (DataRow dr in dt.Rows)
   {
       txtdeptname.Text = dr["Department"].ToString();
   }
        
   con.Close();
}

欢迎任何提示!

【问题讨论】:

  • 该代码有很多错误,甚至忽略了我在下面的回答中指出的内容。首先,您可能出于什么原因将空字符串连接到该查询的末尾?它不会造成伤害,但它就像为变量分配一个数字并显式添加零。没有人会这样做,那么为什么要添加空字符串呢?
  • 其次,您应该始终使用参数将值插入到 SQL 代码中。在这种情况下出现问题的可能性较小,但如果您始终做正确的事,就永远不会因做错事而被抓到。请参阅here 了解我对这个主题的看法。
  • 第三,为什么要使用 DataTable 和循环来填充单个 TextBox?也许您为了简洁而省略了一些代码,但您无疑应该做一些不同的事情。如果您只是打算丢弃 DataTable,那么您几乎肯定应该改用数据读取器。如果有多行,那么您只会看到最后一行带有这样的代码。如果只有一行,为什么要循环?如果你只使用一列,那么不要检索所有列,如果你只检索一个值,那么你应该调用ExecuteScalar
  • 您可能想查看我的 ADO.NET 示例 here 以了解在不同情况下该怎么做。那是前段时间写的,所以某些细节可以改进,但是一般原则是什么时候使用什么类型的对象和方法。

标签: c# ado.net sqlconnection sqlclient


【解决方案1】:

您似乎正在使用一个公共连接对象。不。在您使用的地方创建您的连接对象。使用 using 语句执行此操作,然后连接将在块的末尾关闭并销毁。将您的连接字符串存储在一个公共位置,然后每次都使用它来创建一个新连接,例如

var table = new DataTable();

using (var connection = new SqlConnection(connectionString)
using (var adapter = new SqlDataAdapter("SQL query here", connection)
{
    adapter.Fill(table);
}

// use table here.

除了 using 块之外,此代码中还有许多要注意的地方。

首先,它没有明确打开连接,因为没有意义。数据适配器的 FillUpdate 方法将隐式打开连接(如果当前已关闭),如果连接已打开则隐式关闭连接。使用数据适配器时,显式打开连接的唯一原因是调用多个Fill 和/或Update 方法,因此连接会在其间关闭并重新打开。即使您确实打开了连接,仍然不需要显式关闭它,因为它隐式发生在 using 块的末尾。

其次,这段代码没有创建命令对象,因为没有意义。在您的原始代码中,您创建了一个命令对象,然后您不使用它。如果您已经有一个命令对象,那么您可以将它传递给数据适配器构造函数,但您不这样做。您传递 SQL 查询和连接,因此数据适配器将创建它自己的 SelectCommand

事实上,即使在这里创建一个连接对象也没有意义。数据适配器有一个接受 SQL 查询和连接字符串的构造函数,因此您可以只创建数据适配器并让它在内部完成其余的工作:

var table = new DataTable();

using (var adapter = new SqlDataAdapter("SQL query here", connectionString)
{
    adapter.Fill(table);
}

// use table here.

【讨论】:

  • 感谢您的详细回复!我已经通过删除连接语句解决了它。而且我还根据您在我的帖子中的建议清理了我的代码。非常感谢你!
【解决方案2】:

在您的情况下,您不需要打开和关闭连接。这里不需要。

您的代码应如下所示。

using (SqlConnection con = new SqlConnection(connetionString))
{
    using (DataTable dt = new DataTable())
    {
        using (SqlDataAdapter sda = new SqlDataAdapter(sql, con))
        {
            sda.Fill(dt);

            foreach (DataRow dr in dt.Rows)
            {
                txtdeptname.Text = dr["Department"].ToString();
            }
        }

    }

}

还有一些建议,请不要在查询中使用*,而是使用列名,如果您的情况需要,请在查询中使用NOLOCK并使用参数化查询。

【讨论】:

  • 谢谢你!我删除了连接语句并且它起作用了。
猜你喜欢
  • 2016-01-07
  • 1970-01-01
  • 1970-01-01
  • 2012-06-18
  • 1970-01-01
  • 1970-01-01
  • 2023-01-11
  • 1970-01-01
相关资源
最近更新 更多