使用Visual Studio在运行时创建本地数据库

5
初学者提问 - 请问如何在运行时编程创建本地数据库文件?我希望稍后能够像文本和其他文件一样使用Windows资源管理器对它们进行重命名、删除等操作,并将它们复制到其他计算机上。
我使用的是Visual Studio Community 15和C#,安装了SQL Server Data Tools 14.0.50616.0。计算机上有Microsoft SQL Server 2014。
以下是一个示例程序,只保留了其中与问题相关的代码。它使用一个带有3个按钮(btnCreateDb、btnDeleteDb和btnDoesDbExist)和一个名为cbxDb的组合框来指定数据库名称的Windows窗体应用程序。它会在现有文件夹C:\DbTemp中创建数据库。
它似乎可以创建和删除新的数据库并生成文件,例如mydb1.mdf和mydb1.ldf,然后显示它们存在。但是,如果我使用资源管理器删除这两个文件,则尝试删除或创建数据库时会引发异常;而btnDoesDbExist将显示它仍然存在。
为什么在Windows资源管理器中删除文件后,数据库仍然存在?btnDoesDatabaseExist下的代码没有引用文件路径,所以它必须看到了其他内容,但是在哪里呢?这是程序用户创建、删除和检测这些数据库的正确方法吗?
using System;
using System.Data;
using System.Windows.Forms;

//my additions
using System.Data.SqlClient;

namespace DataProg15
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    public static string form1ConnectionString = "Data Source = (LocalDB)\\MSSQLLocalDB; Integrated Security = True; Connect Timeout = 30; ";
    private string form1DatabasePath = "C:\\DbTemp";

    private void btnCreateDb_Click(object sender, EventArgs e)
    {
        string nameToCreate = cbxDb.Text;
        SqlConnection myConn = new SqlConnection(form1ConnectionString);

        string str = "CREATE DATABASE " +nameToCreate+ " ON PRIMARY " +
            "(NAME = " +nameToCreate+ "_Data, " +
            "FILENAME = '" +form1DatabasePath+ "\\" +nameToCreate+ ".mdf', " +
            "SIZE = 4MB, MAXSIZE = 10MB, FILEGROWTH = 10%) " +
            "LOG ON (NAME = " +nameToCreate+ "_Log, " +
            "FILENAME = '" +form1DatabasePath+ "\\" +nameToCreate+ ".ldf', " +
            "SIZE = 1MB, " +
            "MAXSIZE = 5MB, " +
            "FILEGROWTH = 10%)";

        SqlCommand myCommand = new SqlCommand(str, myConn);

        try
        {
            myConn.Open();
            myCommand.ExecuteNonQuery();
            MessageBox.Show("DataBase '" + nameToCreate + "' was created successfully");
        }
        catch (System.Exception ex)
        {
            MessageBox.Show("Exception in CreateDatabase " + ex.ToString(), "Exception in CreateDatabase", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        finally
        {
            if (myConn.State == ConnectionState.Open)
            {
                myConn.Close();
            }
        }
    }


    private void btnDeleteDb_Click(object sender, EventArgs e)
    {
        string nameToDelete = cbxDb.Text;
        string myConnectionString = form1ConnectionString + "AttachDBFileName = " + form1DatabasePath + "\\" + nameToDelete + ".mdf ";
        string str = "USE MASTER DROP DATABASE " + nameToDelete;

            SqlConnection myConn = new SqlConnection(myConnectionString);
            SqlCommand myCommand = new SqlCommand(str, myConn);
            myConn.Open();

            try
            {
                myCommand.ExecuteNonQuery();
                MessageBox.Show("DataBase '" + nameToDelete + "' was deleted successfully");

            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Exception in DeleteDatabase '" +nameToDelete+ "'", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            finally
            {
                if (myConn.State == ConnectionState.Open)
                {
                    myConn.Close();
                }
            }
    }

    private void btnDoesDbExist_Click(object sender, EventArgs e)
    {
        string nameToTest = cbxDb.Text;
        using (var connection = new SqlConnection(form1ConnectionString))
        {
            using (var command = new SqlCommand(string.Format(
                   "SELECT db_id('" +nameToTest+ "')", nameToTest), connection))
            {
                connection.Open();

                if ((command.ExecuteScalar() != DBNull.Value))
                {
                    MessageBox.Show("DataBase '" +nameToTest+ "' exists");
                }
                else
                {
                    MessageBox.Show("Database '" +nameToTest+ "' does not exist");
                }
            }
        }

    }
}

非常感谢您的回复,你的辛苦付出我们深表感激。

现在我明白了我使用了错误的数据库,所以我尝试使用 SQL Server Compact。已经卸载,重新下载并安装了 SQL Server Compact 包括 SP1,还从 https://visualstudiogallery.msdn.microsoft.com/0e313dfd-be80-4afb-b5e9-6e74d369f7a1 下载并安装了 SQL Server Compact/SQLite Toolbox。但是,当我键入 using System.Data.SqlServerCe 时,Visual Studio 一直显示错误。同时,在我键入 SqlCeEngine 或者 SqlCecommand 时也会显示类似的错误。

在 Visual Studio 中,SQL Server Data ToolsSQL Server Compact & SQLite Toolbox 被显示为已安装的产品,但不包括 SQL Server Compact。我需要将其安装到 Visual Studio 中吗?如果需要,如何进行安装?


你不应该直接操作数据文件。如果你真的想这样做,你必须使用“detach”和“attach”。此时,你的本地数据库 SQL Server 已经知道了这个数据库,但找不到数据文件。 - John
1
Sql Server 是一个复杂的系统。当你创建一个数据库时,你不仅添加了一些文件名,还有很多系统和配置信息。这些信息存储在内部数据库(如 model、master、temp 等)中。使用 Windows Explorer 删除这些文件会使你的 Sql Server 安装处于不稳定状态,因为内部信息仍然存在,但文件已经被删除。如果你需要这种自由,请选择一个不同的数据库系统(基于文件的系统),如 SQLite、Sql Server Compact,甚至 MS-Access。 - Steve
1
我很惊讶,如果数据库服务器正在运行,你还能删除文件。SQL Server通常会锁定这些文件,以防止实时数据库被删除。 - SchmitzIT
1
@steve - Temp和model不会包含有关新数据库的信息。Model基本上只是用于创建新数据库的“模板”。即,如果您需要在创建的所有数据库中存在特定对象,请将其添加到model中。Temp仅在您针对数据库发出查询并且某些操作的部分需要在tempdb中发生时才会使用。 - SchmitzIT
谢谢回复。我正在尝试使用SQL Server Compact,但正如上文所述,遇到了一些困难。 - egginstone
显示剩余2条评论
2个回答

2
在“解决方案资源管理器”中的“引用”下,检查是否列出了“System.Data.SqlServerCe”。如果没有,请右键单击“引用”,然后选择“添加引用”->“浏览”按钮并选择文件“System.Data.SqlServerCe.dll”,该文件可能位于“C:\Program Files\Microsoft SQL Server Compact Edition\v4.0\Desktop”中。现在,“System.Data.SqlServerCe”应该出现在“引用”下方。下面的程序似乎可行,并且更简单。感谢所有人的帮助。
using System;
using System.Data;
using System.Windows.Forms;
//my additions
using System.Data.SqlServerCe;
using System.IO;

namespace DataProg15
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        public static string form1DatabasePath = "C:\\DbTemp\\dbtemp1.sdf";
        public static string form1ConnectionString = "Data Source = " +form1DatabasePath;

        private void btnCreateDb_Click(object sender, EventArgs e)
        {
                SqlCeEngine engine = new SqlCeEngine(form1ConnectionString);
            try
            {
                engine.CreateDatabase();
                MessageBox.Show("DataBase '" +form1DatabasePath+ "' was created successfully");
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("Exception in CreateDatabase " + ex.ToString(), "Exception in CreateDatabase", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            finally
            {
                engine.Dispose();
            }
        }

        private void btnDeleteDb_Click(object sender, EventArgs e)
        {
            if (File.Exists(form1DatabasePath))
            {
                try
                {
                    File.Delete(form1DatabasePath);
                    MessageBox.Show("DataBase '" +form1DatabasePath+ "' was deleted successfully");
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show(ex.ToString(), "Exception in DeleteDatabase '" +form1DatabasePath+ "'", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
        }

        private void btnDoesDbExist_Click(object sender, EventArgs e)
        {
            if (File.Exists(form1DatabasePath))
            {
                    MessageBox.Show("DataBase '" +form1DatabasePath+ "' exists");
            }
            else
            {
                    MessageBox.Show("DataBase '" +form1DatabasePath+ "' does not exist");
            }
        }
    }
}

0

如果数据库处于活动状态,SQL Server将永远不会让您删除数据库的物理文件 - 永远不会。唯一能够这样做的情况是如果数据库已分离(如前所述)

因此,我怀疑您告诉我们的某些内容并不完全正确?

我建议您更改“检查数据库是否存在”的逻辑为:

select * from sys.databases where name = 'yourdatabasename'

即使在删除数据库后,我也会运行此查询,以查看它返回了什么。


谢谢。回复和进一步阅读建议我应该使用仅存在于本地文件中的数据库,因此我正在尝试使用SQL Server Compact,但仍然遇到了上面编辑中所述的困难。 - egginstone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接