1

SQL Server データベースとそのデータベースの古いバックアップがあります。C# WinForms アプリケーションを使用して、バックアップ コピー内の一部のデータを検証する必要がある場合があります。この投稿を使用してバックアップ ファイルを復元します: 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(); }
        }
    }

今のところすべて正常に動作しています。問題は、復元されたデータベースを削除しようとすると、データベースがまだ使用されているため削除できないというエラーが返されることです。これは、データベースを削除する方法です。

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().

PS私はdatabase.ReadDataBaseIstoric()現在のデータベース(復元されたバックアップではない)からデータを読み取るためにも関数を使用していますが、エラーや例外なしでうまく機能します。

4

2 に答える 2

2

You've three issues here. First you aren't disposing as suggested by @jyparask.

The other is by default you are using the connection pool. This means even if you close the connection, it stays alive in the pool for a default time (2 minutes I think). So if I was doing this, I'd be adding pooling = false to that connection string as well. Because of that I might against all recommendation, instance a connection and then pass it about and dispose of it during the drop operation

Last but not least you are connecting to the database you are trying to drop aren't you? Best bet would be to create a new connection to the Master database in order to drop the one you want.

于 2013-09-15T11:54:41.563 に答える
2

関数を次のように変更してみてください。

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 はオブジェクトを閉じて破棄します。

于 2013-09-15T11:30:16.423 に答える