【问题标题】:Connection not close between SqlCommandSqlCommand 之间的连接未关闭
【发布时间】:2023-03-16 13:31:02
【问题描述】:

我以编程方式创建一个数据库,然后在数据库中创建一个表。创建了数据库,但没有创建表。

// Create Database
try
{
    using (SqlCommand cmd = new SqlCommand(connstr, sqlConn))
    {
        try
        {
            sqlConn.Open();
            cmd.ExecuteNonQuery();
            MessageBox.Show("DataBase is Created Successfully", "MyProgram", MessageBoxButton.OK, MessageBoxImage.Information);
        }
        catch (System.Exception ex)
        {
            MessageBox.Show(ex.ToString(), "MyProgram", MessageBoxButton.OK, MessageBoxImage.Information);
        }
        finally
        {
            if (sqlConn.State == ConnectionState.Open)
            {
                sqlConn.Close();
            }
        }
    }
}
catch(Exception ex)
{
    MessageBox.Show(ex.ToString());
}

// Create table
try
{
    using (SqlCommand cmd = new SqlCommand(
                    "CREATE TABLE dbo.MyTable ("
                    + "ID int IDENTITY(1,1) PRIMARY KEY,"
                    + "MyProduct nvarchar(100) NOT NULL,"
                    + "MyDateTime datetime NOT NULL);"
                    + "", sqlConn))
    {
        sqlConn.Open();
        cmd.Connection.Open();
        cmd.ExecuteNonQuery();
        cmd.Connection.Close();
    }
}
catch (Exception ex)
{

    MessageBox.Show(ex.ToString());
}

但我收到错误消息说我的连接没有关闭。

我尝试反复将 sqlConn.Close() 添加到每个 {block} 的末尾,但仍然出现相同的错误。创建数据库后如何正确关闭连接然后再次重新打开连接以创建表?

[编辑]

在回答输入之后,我已经重组了我的代码,我确信在不重复 Open() 的情况下包装属性。

    // Create Database
    try
        {
        using (SqlConnection sqlConn = new SqlConnection(sqlConnectionStr))
        {
            using (SqlCommand cmd = new SqlCommand(connstr, sqlConn))
            {
                try
                {
                    sqlConn.Open();
                    cmd.ExecuteNonQuery();
                    MessageBox.Show("DataBase is Created Successfully", "MyProgram", MessageBoxButton.OK, MessageBoxImage.Information);
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show(ex.ToString(), "MyProgram", MessageBoxButton.OK, MessageBoxImage.Information);
                }
                finally
                {
                    if (sqlConn.State == ConnectionState.Open)
                    {
                        sqlConn.Close();
                    }
                }
            }
        }
    }
    catch(Exception ex)
    {
        MessageBox.Show("(1)\n" + ex.ToString());
    }

// Create Table
    try
    {
        using (SqlConnection sqlConn = new SqlConnection(sqlConnectionStr))
        {

            using (SqlCommand cmd = new SqlCommand("CREATE TABLE dbo.MyTable ("
                            + "ID int IDENTITY(1,1) PRIMARY KEY,"
                            + "MyProduct nvarchar(100) NOT NULL,"
                            + "MyDateTime datetime NOT NULL);"
                            + "", sqlConn))
            {
                sqlConn.Open();
                cmd.ExecuteNonQuery();
                sqlConn.Close();
            }
        }

    }
    catch (Exception ex)
    {
        MessageBox.Show("(2)\n" + ex.ToString());
    }

然后我收到错误数据库中已经有一个名为“MyTable”的对象。但是当我查看 SSMS 时,该表不存在。我现在很困惑。

【问题讨论】:

  • 最好显示哪个是 MyDatabase.cs:line 94。
  • 请停止写catch Exception - 这是一个糟糕的糟糕的反模式。您应该只捕获您可以有意义地处理的特定异常。
  • 根据各种答案告诉您将 Connections 与 Using 块结合使用,我建议阅读 IDisposable 以及 Using 块如何与该接口一起使用。这将告诉你为什么不需要在 Connection 和其他有意义的细节上调用 Close()。

标签: c# wpf sql-server-2016


【解决方案1】:

当您创建表时,您尝试打开连接两次。 cmd.Connection 属性指向与sqlConn 相同的连接。删除其中一个。

using (SqlCommand cmd = new SqlCommand(
                "CREATE TABLE dbo.MyTable ("
                + "ID int IDENTITY(1,1) PRIMARY KEY,"
                + "MyProduct nvarchar(100) NOT NULL,"
                + "MyDateTime datetime NOT NULL);"
                + "", sqlConn))
{
    sqlConn.Open();
    cmd.Connection.Open();  // don't need this...
    cmd.ExecuteNonQuery();
    cmd.Connection.Close();
}

根据docs,这是预期行为。

无效操作异常

如果不指定数据源或服务器,则无法打开连接。

连接已打开。

【讨论】:

    【解决方案2】:

    我没有看到您关闭第二个查询的连接。您可以使用 SqlConnection 的 using 语句进行包装。

    仅供参考:如果使用 using 语句,则无需显式关闭连接。

    string cmdText = "SELECT * FROM SomeTable";
    using (var conn = new SqlConnection(connectionString))
    using (var cmd = new SqlCommand(cmdText, conn))
    {
        conn.Open();
        cmd.ExecuteNonQuery();
        MessageBox.Show(...);
    }
    

    【讨论】:

    • 谢谢。我已经重组了我的代码并使用 using 语句将我的 cmd 包装在 conn 中,然后我得到一个不同的错误,指出在创建表时 try 块捕获了“MyTable 已经存在”。在 SSMS 中,Tables 下显然没有 MyTable。我尝试删除整个数据库并开始清理然后我得到同样的错误......
    • 您能否确保该表不是在与您预期不同的数据库中创建的,例如 master 数据库?一般情况下,可以先检查表是否存在,再创建IF (NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'MyTable')) BEGIN CREATE TABLE ... END
    • 如我所说,如果使用 using 语句,则不需要sqlConn.Close()
    • 你是对的。主数据库中有一个表。所以我明确输入了 MyDatabase.dbo.MyTable 而不是 dbo.MyTable ...我不明白为什么连接字符串已经指定了我的数据库名称,它仍然在 master 数据库而不是 MyDatabase 中创建它??
    • 能否显示连接字符串 - 屏蔽用户名和密码?或者,您可以查看示例 SQL Server 连接字符串 here
    【解决方案3】:

    试试这个代码。也许会有帮助。

    public void NewClass()
    {
        try
        {
            string query = "if exists(SELECT db_id('{0}'),'TEST') ";
            query += "begin ";
            query += "print 'All Ready Exists' ";
            query += "end ";
            query += "else ";
            query += "begin ";
            query += "create database TEST ";
            query += "end ";
    
            lblno.Text = query+"<br>";
            con.Open();
            SqlCommand cmd = new SqlCommand(query, con);
            int ans = cmd.ExecuteNonQuery();
            cmd.Cancel(); cmd.Dispose();
            con.Close(); con.Dispose();
    
            string table = "if exists (select OBJECT_ID('test')) begin ";
            table += "print 'all ready' end ";
            table += "else begin ";
            table += "CREATE TABLE dbo.MyTable (ID int IDENTITY(1,1) PRIMARY KEY,MyProduct nvarchar(100) NOT NULL,MyDateTime datetime NOT NULL) ";
            table += "end ";
    
            con = new SqlConnection("Data Source=DESKTOP-0R1BJNQ\\HARDIKPATEL;Initial Catalog=" + dbnm + ";Integrated Security=True");
            con.Open();
            cmd = new SqlCommand(table, con);
            cmd.ExecuteNonQuery();
            cmd.Cancel(); cmd.Dispose();
            con.Close(); con.Dispose();
    
        }
        catch(Exception err)
        {
            lblmsg.Text = err.ToString();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-21
      • 1970-01-01
      • 2013-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多