I am developing a simple piece of software which uses Entity Framework code first and sql server compact 4. At the moment this setup works. Entity framework creates the sql
connectionString="Data source=Database.sdf;"
This tells your app to look for Database.sdf in your app’s current working directory; which could be anywhere and may not be writeable. You need to look at a location you specify:
connectionString="Data source=|DataDirectory|Database.sdf;"
ADO.NET looks for pipe characters in connection strings and expands them to the value of the property of that name in the application’s domain. So what’s the value of the DataDirectory
property? It’s supposed to be set by whatever deployed your application:
|DataDirectory|
and never a hard-coded path.Any Visual Studio files in your project with a “copy to output directory” property will be copied to DataDirectory. In most cases DataDirectory will be a read-only folder. This is fine if your data is read-only, but if you want to write to it you will have to copy your data to a writeable location. Probably the best place is Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData))
. There are several ways of doing this:
CREATE DATABASE
or new SqlCeConnection()
or whatever.SpecialFolder.ApplicationData
folder and, if not, copy it there.If you search the web for sample code on creating local database you will run across a lot of bad advice. Do not do the following:
new SqlCeConnection(@"Data source=c:\users\me\myApp\Database.sdf;"); // Do NOT do this!
I hope I don’t have to explain why hard-coding the path to your data is wrong; but be aware that unless you specify a full path in your connection string, the path is relative to your current working directory.
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)");
...
}
Do not try to modify the data in DataDirectory
. Not only is this directory not always modifiable by users, it is owned by the installer not by the user. Repairing or uninstalling the application will delete all the user’s data; users don’t like that. Instead, copy the installed data to a folder writable by the user and make all changes to the copy.
AppDomain.CurrentDomain.SetData("DataDirectory",
// Wrong, this overwrites where the user installed your app!
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
Do not change the value of DataDirectory
in your code, it is set by the installer and if you change it you won’t know where your data was installed. If you are creating an empty database, just open it in your final location. If you are going to make a copy, open the installed database, save it to the user’s location, close the installed database, and open the copy.
I also discourage saving data to Environment.SpecialFolder.CommonApplicationData
. This may not be writable by users, and unless there is a very very good reason all users must be allowed to change other users’ data, each user should have their own database.
Use below:
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>