EF Code First能否在ClickOnce应用程序中使用LocalDB



所以,我正在尝试EF Code First,这样我就可以让代码驱动程序更新数据库。我正在使用LocalDB开发ClickOnce应用程序,所以我认为这可能是对我来说最好的解决方案,因为否则对MDF文件的更改将导致它在部署时在客户端上被覆盖,从而丢失之前输入的所有内容。

然而,我现在对代码优先迁移的所有新问题都有自己的看法。我在MSDN上完成了代码优先迁移,并成功地创建了初始Configuration,以及初始数据库创建。

当我尝试进行第一次实际迁移时,问题就开始了。我在其中一个模型中添加了一个字段,并尝试进行显式迁移,以便在下次发布时处理模式更改。好

PM>添加迁移AddIsPercentField

无法生成显式迁移,因为以下显式迁移处于挂起状态:[20161052011180_InitialCreate]。在尝试生成新的显式迁移之前,应用挂起的显式移植。

好的。。。我将运行更新并重试:

PM>更新数据库

指定"-Verbose"标志以查看应用于目标数据库的SQL语句
应用显式迁移:[20161052011180_InitialCreate]
应用显式迁移:201601052011180_InitialCreate
无法更新数据库以匹配当前模型,因为存在挂起的更改,并且已禁用自动迁移。将挂起的模型更改写入基于代码的迁移,或者启用自动迁移。将DbMigrationsConfiguration.AutomaticMigrationsEnabled设置为true可启用自动迁移
可以使用"添加移植"命令将挂起的模型更改写入基于代码的移植。

PM>添加迁移AddIsPercentField

无法生成显式迁移,因为以下显式迁移处于挂起状态:[20161052011180_InitialCreate]。在尝试生成新的显式迁移之前,应用挂起的显式移植。

这很熟悉,因为这就是它早些时候告诉我的错误(公然的谎言?)。好吧,也许如果我撤消更改并再次更新,它将移动到有效状态:

PM>更新数据库

指定"-Verbose"标志以查看应用于目标数据库的SQL语句
应用显式迁移:[20161052011180_InitialCreate]
应用显式迁移:201601052011180_InitialCreate
正在运行种子方法。

好的,这次没有警告。应该是金色的。字段已添加回,项目已重建。我们开始了:

PM>添加迁移AddIsPercentField

无法生成显式迁移,因为以下显式迁移处于挂起状态:[20161052011180_InitialCreate]。在尝试生成新的显式迁移之前,应用挂起的显式移植。

所以。。。是否真的有一种有效的方法来为第一个之后的任何更改生成显式迁移?

编辑:我相信我在这方面取得了一些进展。我确实注意到,在运行Update-Database之后,在我的.mdf中没有生成__MigrationHistory表,尽管它说一切都很好。我认为问题实际上是关于本地数据库在应用程序中的工作方式。连接字符串引用AttachDbFilename=|DataDirectory|。我认为这是在临时部署.mdf,更新临时部署,从而最终不提交更改。

我正在研究一个我心目中的解决方案,即让迁移针对放在静态位置的blank.mdf的副本进行,这样static.mdf将用于跟踪和确定更改,而blank.mdf将用于部署时发送给客户端的内容。

我发现问题的根源是控制台命令实际上无法对我的数据文件进行更改,从而跟踪迁移。这是由于数据文件的连接字符串引用了部署位置,因此更新的文件只是临时的。

这在一定程度上是一件好事,因为在我的项目中使用代码优先迁移的全部目的是避免在发布时对我的.mdf(作为占位符,它应该保持为空)进行哈希签名更改,这样以前版本的数据就永远不会被覆盖和丢弃。然而,这也带来了一个明显的(回顾过去)问题,即EF无法跟踪变化,因为从来没有__MigrationHistory表。

我得到的解决方案是有两个.mdf文件。空白的一个用于部署,第二个用于与代码优先迁移交互。因此,我有构建操作Content的初始MyData.mdf和构建操作None的第二个MyDataDesignTime.mdf。(不应部署"设计时"迁移数据库。)

使用这种方法,我发现我现在可以成功地进行迁移,调用Update-DatabaseAdd-Migration,确保传递-ConnectionString参数,AttachDbFilename指向我的设计时数据库的完整路径。

后来,由于懒得在每个迁移命令上提供一个长的-ConnectionString参数,我将设计时路径添加到配置连接字符串中,并更新了DbContext,使其最初使用设计时路径,但我会在运行时开始更改该路径,以使用我的实际目标数据文件:

public partial class MyData : DbContext
{
    public const string DesignTimeConnection = "MyDataConnectionStringDesignTime";
    public static string ConnectionName { get; set; } = DesignTimeConnection;
    public MyData()
        : base("name=" + ConnectionName)
    {
    }
    ...
}

在应用程序初始化时:

MyData.ConnectionName = "MyDataConnectionString";

这很有效,而且让事情对我来说更简单。然而,我留下的一个小问题是,在app.config文件中留下了一个仅适用于我的环境的完整静态路径。目前还不是问题,因为我是这个项目的唯一开发人员,但这是一种我不满意的代码气味。是否有一些路径变量可以使用,这样它仍然指向实际的设计时数据(而不是任何临时的、部署的文件),但相对于活动的、打开的项目是这样做的?

最新更新