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 DATABASE
或new 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
。這可能不是用戶可寫的,除非有非常好的理由,所有用戶必須被允許更改其他用戶的數據,否則每個用戶都應該擁有自己的數據庫。
但是這種方式我必須在代碼中構建連接字符串。這不會讓我們很容易切換數據庫的位置,就像我現在做的那樣。我在我的常規項目和我的測試項目中都有一個單獨的app.config文件,它們都指向不同的數據庫。 –