所以,我找到了一个技巧。
ADO允许连接字符串以|DataDirectory|开头,这是一个替换字符串,由当前AppDomain的"DataDirectory"设置替换。
通常情况下,它默认为.EXE文件的位置,但网站、单击安装等会发生变化。
因为EntityFramework建立在ADO之上,所以它也适用于EF。
让它起作用的原因是,您可以在程序启动时更改它,使其指向任何您喜欢的位置。
我正在做的是在每个项目的App.config中放置一个相对于.EXE文件位置的路径的appSetting,并在程序启动时使用它来设置它:
<appSettings>
<!-- path to the directory containing the database, relative to the location of the .exe -->
<add
key="dataDir"
value="..\..\..\DataBase"
/>
</appSettings>
<connectionStrings>
<add
name="EmbeddedDatabaseConnectionString"
connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|EmbeddedDatabase.mdf;Integrated Security=True"
providerName="System.Data.SqlClient"
/>
</connectionStrings>
然后在代码中:
public class ReadWithADO
{
static ReadWithADO()
{
var appSetting = ConfigurationManager.AppSettings["dataDir"];
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
var path = Path.Combine(baseDir, appSetting);
var fullPath = Path.GetFullPath(path);
AppDomain.CurrentDomain.SetData("DataDirectory", fullPath);
}
static void Main(string[] args)
{
var connectionString = ConfigurationManager.ConnectionStrings["EmbeddedDatabaseConnectionString"].ConnectionString;
using (var con = new SqlConnection(connectionString))
{
con.Open();
var cmd = new SqlCommand("SELECT * FROM Customer", con);
var rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Console.WriteLine(rdr[0]);
}
}
Console.Write("<Press any key>");
Console.ReadKey();
}
}
Entity Framework中同样适用:
<connectionStrings>
<add
name="EmbeddedDatabaseEntities"
connectionString="metadata=res://*/EmbeddedDatabase.csdl|res://*/EmbeddedDatabase.ssdl|res://*/EmbeddedDatabase.msl;provider=System.Data.SqlClient;provider connection string="data source=(LocalDB)\v11.0;attachdbfilename=|DataDirectory|EmbeddedDatabase.mdf;integrated security=True;connect timeout=30;MultipleActiveResultSets=True;App=EntityFramework""
providerName="System.Data.EntityClient"
/>
</connectionStrings>
<appSettings>
<!-- path to the directory containing the database, relative to the location of the .exe -->
<add
key="dataDir"
value="..\..\..\DataBase"
/>
</appSettings>
并且:
public class ReadWithEF
{
static ReadWithEF()
{
var appSetting = ConfigurationManager.AppSettings["dataDir"];
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
var path = Path.Combine(baseDir, appSetting);
var fullPath = Path.GetFullPath(path);
AppDomain.CurrentDomain.SetData("DataDirectory", fullPath);
}
private static void Main(string[] args)
{
using (var db = new EmbeddedDatabaseEntities())
{
foreach (var customer in db.Customers)
{
Console.WriteLine(customer.CustomerId);
}
}
Console.Write("<Press any key>");
Console.ReadKey();
}
}
通过这种方法,您可以在开发中使用本地数据库,或者在运行不是真正的单元测试时使用。 (严格来说,如果测试正在访问数据库,则它是集成测试,而不是单元测试,但即使违反教条纯洁性,这些测试也非常有用。)
由于您的生产安装将使用连接字符串指向真实的数据库服务器,而不是本地文件,因此所有这些与DataDirectory相关的操作都没有任何影响。