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

Jef*_*ege 3 visual-studio visual-studio-2013 sql-server-data-tools

我一直在阅读Visual Studio 2013的新Sql Server数据工具是多么精彩,以及有关新的localdb数据库服务器等等,所以我一直在尝试做我认为是整个事情的重点 - 在VS解决方案中嵌入本地测试/开发数据库,​​这样当我将项目签出到一个干净的目录中时,在新机器上,我可以运行我的应用程序,连接到解决方案中的数据库.

但我无法弄清楚如何做到这一点.

任何人都可以给我任何提示吗?或指导教程?

添加一些说明

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

本地数据概述

但是,不幸的是,它不起作用.我完全遵循了说明,这一切似乎都有效,直到我将解决方案文件夹移动到新位置,此时它丢失了对数据库的跟踪.

问题是连接字符串,它包含数据库创建时的绝对路径.哪个没用.我需要能够在任何机器上检查任何位置的项目,并让它在那里构建和运行.

<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>
Run Code Online (Sandbox Code Playgroud)

显然,之前已经提出过这个问题:

在配置文件中使connectionstring的AttachDbFilename相对

但这个问题没有答案.

Jef*_*ege 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>
Run Code Online (Sandbox Code Playgroud)

然后在代码中:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这在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>
Run Code Online (Sandbox Code Playgroud)

和:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以拥有一个在开发中使用的本地数据库,或者运行不是单元测试的单元测试.(严格地说,如果测试是在攻击数据库,那么它是一个集成测试,而不是单元测试,但是这些测试非常有用,即使它们确实违反了教义纯度.)

并且由于您的生产安装将使用指向真实数据库服务器的连接字符串,而不是本地文件,因此使用DataDirectory的任何混乱都不会产生任何影响.