如何在Visual Studio解决方案中嵌入数据库?

3
我一直在阅读关于Visual Studio 2013新的Sql Server Data Tools和新的localdb数据库服务器等方面的内容,因此我一直在尝试做整个事情的重点 - 将本地测试/开发数据库嵌入到VS解决方案中,这样当我将项目检出到一个干净的目录中,在新机器上运行应用程序时,可以连接到解决方案中的数据库。

但是我一直没有弄清楚如何做到这一点。

有人能给我一些提示吗?还是指向教程的方向?

添加一些澄清

在MSDN上有一个关于如何在项目中包含localdb数据库的教程,链接在这里:

Local Data Overview

但是,不幸的是,它不起作用。我按照说明完全操作了一遍,看起来都没问题,但是当我将解决方案文件夹移动到新位置时,它就失去了对数据库的跟踪。

问题在于连接字符串,它包含了数据库创建时的绝对路径。这是无用的。我需要能够将项目检出到任何位置、任何机器上,并在那里构建和运行。
<connectionStrings>
    <add name="ConnectLocalData.Properties.Settings.SampleDatabaseConnectionString"
        connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=E:\dev\Experiments\LocalDbWalkthrough\SampleDatabaseWalkthrough\SampleDatabase.mdf;Integrated Security=True;Connect Timeout=30"
        providerName="System.Data.SqlClient"
    />
</connectionStrings>

显然,这个问题之前已经被问过了:

如何在配置文件中将连接字符串的AttachDbFilename设置为相对路径

但是那个问题没有答案。

2个回答

6
所以,我找到了一个技巧。
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=&quot;data source=(LocalDB)\v11.0;attachdbfilename=|DataDirectory|EmbeddedDatabase.mdf;integrated security=True;connect timeout=30;MultipleActiveResultSets=True;App=EntityFramework&quot;"
        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相关的操作都没有任何影响。

把ReadWithEF()方法中的代码放到Program.cs文件中会不会更好呢? - solujic

0

了解“二进制资源”。除了像图标、光标和字符串表之类的资源外,任意二进制 blob 都可以添加到可执行文件中。一个例子是嵌入预编译的 hlsl 着色器。另一个例子是 sysinternals 进程浏览器。64 位可执行文件是 32 位可执行文件内部的一种资源。

如果您的数据库 API 需要挂载文件,则可能需要将此资源复制到磁盘上。否则直接使用即可。示例代码可以在平台 SDK 中找到。


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