【问题标题】:Sql Server Drop Database failureSql Server 删除数据库失败
【发布时间】:2013-09-19 15:26:19
【问题描述】:

我有一个 SQL Server 数据库和该数据库的旧备份。有时我必须使用 C# WinForms 应用程序验证备份副本中的一些数据。我使用这篇文章恢复备份文件:How to restore to a different database in sql server?

我的恢复功能如下所示:

SqlConnection myConn = new SqlConnection("Server=.\\sqlexpress;Database=master;Trusted_Connection=True;");
try
{
    if (!Databases.CheckDatabaseExists(myConn, fileName))
    {
        myConn.Open();
        SqlCommand cmd = new SqlCommand("RESTORE FILELISTONLY FROM DISK='" + fileName + ".bak'", myConn);
        SqlDataReader reader = cmd.ExecuteReader();
        cmd.CommandText = "restore database " + Path.GetFileName(fileName) + " from disk = '" + fileName + ".bak' with move'";
        int i = 0;
        while (reader.Read())
        {
            if (i == 0)
            {
                cmd.CommandText += reader[0].ToString() + "' to '" + filePath + "\\" + Path.GetFileName(fileName) + ".mdf', move ";
                i++;
            }
            else
            {
                cmd.CommandText += "'" + reader[0].ToString() + "' to '" + filePath + "\\" + Path.GetFileName(fileName) + ".mdf.ldf'";
            }
        }
        reader.Close();
        cmd.ExecuteNonQuery();
        myConn.Close();
        database.ReadDataBaseIstoric(dataGridView1, Path.GetFileName(fileName));
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    finally
    {
        if (myConn.State == ConnectionState.Open) { myConn.Close(); }
    }

database.ReadDataBaseIstoric(dataGridview1,Path.GetFileName(filename)); 

从恢复的数据库中读取数据,如下所示:

public void ReadDataBaseIstoric(DataGridView dataGridView1, string dataBaseName)
    {
        dataGridView1.Rows.Clear();
        SqlConnection conn = new SqlConnection("Server=.\\sqlexpress;Trusted_Connection=true;database=" + dataBaseName + ";");
        SqlDataReader reader = null;

        try
        {
            conn.Open();

            SqlCommand  cmd = new SqlCommand("select * from istoric", conn);
            conn.Close();
            reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                string[] str = new string[5] { reader[0].ToString(), reader[1].ToString(), reader[2].ToString(), reader[3].ToString(), reader[4].ToString() };
                dataGridView1.Rows.Add(str);
            }
            reader.Close();
            conn.Close();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
        finally
        {
            if (reader != null && !reader.IsClosed) { reader.Close(); }
            if (conn.State == ConnectionState.Open) { conn.Close(); }
        }
    }

目前一切正常。问题是,当我尝试删除恢复的数据库时,它返回 en 错误,表示无法删除数据库,因为它仍在使用中。这就是我要删除数据库的方式:

private void Arhiva_FormClosing(object sender, FormClosingEventArgs e)
{
        bool closed = false;
        if (!closing) { e.Cancel = true; closing = false; closed = true; }
        SqlConnection myConn = new SqlConnection("Server=.\\sqlexpress;Database=master;Trusted_Connection=True;");

        try
        {
            if (Databases.CheckDatabaseExists(myConn, Path.GetFileName(fileName)))
            {
                myConn.Open();
                SqlCommand cmd = new SqlCommand("DROP DATABASE "+Path.GetFileName(fileName), myConn);
                cmd.ExecuteNonQuery();
                myConn.Close();
                label1.Visible = false;
            }
            else
            {
                MessageBox.Show("Exista deja o baza de date cu numele '" + fileName + "'.", "VivaFEED", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
        finally
        {
            if (myConn.State == ConnectionState.Open) { myConn.Close(); }
        }
        if (closed) { this.Close(); }
  }

我在读取数据之前尝试删除恢复的数据库,效果很好,所以我认为问题应该出在database.ReadDataBaseIstoric()

附:我还使用database.ReadDataBaseIstoric() 函数从当前数据库(不是恢复的备份)读取数据,它工作得很好,没有任何错误或异常。

【问题讨论】:

  • 除了我的解决方案,我可以看到你在执行阅读器之前关闭了连接,所以那里可能有问题。

标签: c# sql sql-server database winforms


【解决方案1】:

尝试将您的功能更改为:

public void ReadDataBaseIstoric(DataGridView dataGridView1, string dataBaseName)
{
    dataGridView1.Rows.Clear();

    using(SqlConnection conn = new SqlConnection("Server=.\\sqlexpress;Trusted_Connection=true;database=" + dataBaseName + ";"))
    using(SqlCommand  cmd = new SqlCommand("select * from istoric", conn))
    {
        SqlDataReader reader = null;
        try
        {

            conn.Open();
            using(SqlDataReader reader = cmd.ExecuteReader())
            {
                while (reader.Read())
                {
                    string[] str = new string[5] { reader[0].ToString(), reader[1].ToString(), reader[2].ToString(), reader[3].ToString(), reader[4].ToString() };
                    dataGridView1.Rows.Add(str);
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
}

using 将关闭并处理对象。

【讨论】:

  • 最好在 catch 块中检查 conn != null 并调用 conn.dispose() 。说真的,对于 cmd 和 reader 来说也是如此。或者在 using 语句周围放置内部 catch 块,并在内部语句中调用 throw。
  • @TonyHopkinson 所以你说我应该离开最后的部分?
  • 不使用是可以的,只需要确保是否抛出异常,所有finally隐式或显式仍然被执行。仔细观察后,看起来他们可能会在这种情况下。
  • 您的解决方案并添加 pooling=false;在连接字符串中完成了这项工作。谢谢
【解决方案2】:

这里有三个问题。 首先,您没有按照@jyparask 的建议进行处置。

另一个是你默认使用的连接池。这意味着即使您关闭连接,它也会在池中保持默认时间(我认为是 2 分钟)。因此,如果我这样做,我也会在该连接字符串中添加 pooling = false 。因此,我可能会反对所有建议,实例化一个连接,然后在删除操作期间传递它并处理它

最后但并非最不重要的是,您正在连接到您要删除的数据库,不是吗?最好的办法是创建一个到主数据库的新连接,以便删除你想要的那个。

【讨论】:

  • 当我尝试删除数据库时,我正在连接到主数据库。请参阅私有 void Arhiva_FormClosing(object sender, FormClosingEventArgs e) 事件。其他 2 个问题仍然存在。
  • 原来如此,我很抱歉。
猜你喜欢
  • 1970-01-01
  • 2021-12-26
  • 1970-01-01
  • 1970-01-01
  • 2023-04-11
  • 2011-03-10
  • 1970-01-01
  • 2011-08-13
  • 1970-01-01
相关资源
最近更新 更多