在AppData文件夹中创建SQL Server Compact文件

11

我正在开发一个简单的软件,该软件使用Entity Framework code first和sql server compact 4。目前这个设置是有效的。如果还不存在,Entity Framework会创建sql server compact文件。数据库的路径是从存储在app.config文件中的连接字符串中定义的。它的结构如下:

<connectionStrings>
  <add name="DataContext" 
       connectionString="Data source=Database.sdf;"
       providerName="System.Data.SqlServerCe.4.0"/>
</connectionStrings>

然而,我想将数据库放在当前用户的应用数据文件夹内的一个文件夹中(在我的win7机器上是C:\Users\User\AppData\Roaming文件夹)。我尝试将连接字符串的数据源设置为类似于%APPDATA%\Database.sdf的东西,但这不起作用,我得到了一个“路径中有非法字符”的异常。

我希望坚持使用连接字符串方法,因为我想在单元测试中使用不同的数据库而不是实际应用程序中的数据库。这样可以通过在项目根目录中放置app.config文件来轻松修改数据库。

有人能指导我正确的方向吗?


但是这种方式我必须在代码中构建连接字符串。这样做不会使切换数据库位置变得容易,就像我现在所做的那样。我在我的常规项目和测试项目中都有一个单独的app.config文件,它们都指向不同的数据库。 - Jesse van Assen
2个回答

22

请使用以下代码:

AppDomain.CurrentDomain.SetData("DataDirectory", Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));

<connectionStrings>
  <add name="DataContext" 
       connectionString="Data source=|DataDirectory|Database.sdf;"
       providerName="System.Data.SqlServerCe.4.0"/>
</connectionStrings>

谢谢,这个可行。实际应用是一个WPF应用程序,我将AppDomain行放在了App.xaml.cs启动方法中。 - Jesse van Assen
4
在“DataDirectory”(|DataDirectory|)之前需要添加另一个管道符号。我觉得这可能对某些人有所帮助,因为我也曾卡在这里很长时间!http://msdn.microsoft.com/en-us/library/cc716756(v=vs.100).aspx - Rachel

3
    connectionString="Data source=Database.sdf;"

这告诉您的应用程序在当前工作目录中查找Database.sdf;这可能在任何地方,并且可能不可写。您需要查看指定的位置:

    connectionString="Data source=|DataDirectory|Database.sdf;"

ADO.NET会在连接字符串中查找管道字符,并将其扩展为应用程序领域中该名称属性的值。那么DataDirectory属性的值是什么?它应该由部署应用程序的程序来设置:
- .MSI安装程序将其设置为应用程序安装文件夹。如果您允许用户选择安装文件夹,则他们也会选择DataDirectory。这就是为什么您应该始终使用|DataDirectory|而不是硬编码路径的原因。 - ClickOnce为项目定义了一个特殊的数据文件夹。 - Web应用程序使用App_Data文件夹。 - Visual Studio调试器使用调试文件夹。
在您的项目中有“复制到输出目录”的属性的任何Visual Studio文件都将被复制到DataDirectory中。在大多数情况下,DataDirectory将是只读文件夹。如果您的数据是只读的,那么这很好,但是如果您想要写入它,您必须将数据复制到可写位置。可能最好的地方是Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData))。有几种方法可以做到这一点:
- 如果要创建空的新数据文件,只需使用API的标准CREATE DATABASEnew SqlCeConnection()等。 - 如果您想要从预填充的种子或初始数据库开始,请将种子数据库包含在您的项目中。在应用程序启动时,检查数据库是否存在于SpecialFolder.ApplicationData文件夹中,如果不存在,则将其复制到那里。
如果您在搜索有关创建本地数据库的示例代码,则会遇到许多错误的建议。不要执行以下操作:
new SqlCeConnection(@"Data source=c:\users\me\myApp\Database.sdf;");  // Do NOT do this!

我希望不用解释为什么在代码中写死数据路径是错误的;但请注意,除非您在连接字符串中指定完整路径,否则路径将相对于当前工作目录。

using (var conn = new SqlCeConnection(@"Data source=|DataDirectory|Database.sdf;"))
{
    conn.Open();
    // No No No! This throws an Access Exception for Standard users,
    // and gets deleted when you repair the app!
    var cmd = conn.CreateCommand("INSERT INTO Table (column1, column2) VALUES (@p1, @p2)");
    ...
}

不要尝试修改DataDirectory中的数据。这个目录并不总是可被用户修改,并且它是由安装程序而非用户拥有。如果修复或卸载应用程序,所有用户数据都将被删除;用户不喜欢这样。相反,将已安装的数据复制到用户可写入的文件夹中,并对副本进行所有更改。

AppDomain.CurrentDomain.SetData("DataDirectory",
    // Wrong, this overwrites where the user installed your app!
    Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));

请勿更改DataDirectory的值,它由安装程序设置,如果您更改它,则无法知道数据安装在哪里。如果要创建空数据库,请在最终位置打开它。如果要进行复制,请打开已安装的数据库,在用户位置保存副本,关闭已安装的数据库,然后打开副本。
我也不建议将数据保存到Environment.SpecialFolder.CommonApplicationData中。这可能无法被用户写入,并且除非有非常好的理由允许所有用户更改其他用户的数据,否则每个用户都应该拥有自己的数据库。

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