【问题标题】:Do I need a migration for EF code first when the database does not exist in SQL Azure?当 SQL Azure 中不存在数据库时,是否需要先迁移 EF 代码?
【发布时间】:2015-11-18 20:19:50
【问题描述】:

我已经尝试了许多 EF 迁移 v6.0.1 的变体(从无数据库到空数据库到现有数据库),我遇到了一个特殊问题,即 Azure 数据库实例无法正确使用 Octopus deploy 在首次部署时创建。

有很多地方可能会出错,所以我想如果可以的话,我会和你们一起检查一些 EF Code First 迁移的基础知识:

如果我创建了代码优先模型,并且知道数据库在 Azure 上的目标数据库服务器中不存在。使用默认的“CreateDatabaseIfNotExists”方法禁用 AutomaticMigrations;

如果我随后使用包含我的 DbContext 和迁移配置的程序集调用“migrate.exe”,我会得到一个使用模型当前状态创建的新数据库吗?还是我会得到一个没有任何内容的新数据库?即我是否需要为模型的初始状态显式“添加迁移”?

我在文档中读到数据库实例应该由迁移过程自动创建,但没有人明确说明(至少对我而言)这个新创建的数据库将使用当前模型生成而没有正式的“初始”状态的迁移创建。

所以问题是:我是否需要为 migrate.exe 生成显式迁移模型才能工作?

通过我尝试的任何方式,我得到了一个数据库,但应用程序启动时显示不友好的消息“无法检查模型兼容性,因为数据库不包含模型元数据。只能检查使用 Code First 或 Code 创建的数据库的模型兼容性第一次迁移。”记住这是最初(从头开始)创建数据库的同一个应用程序库,我不明白这是怎么发生的!

我确实通过 SQL Server 管理工作室手动删除了几次目标数据库,这很糟糕吗?我是否删除了一些需要恢复的重要用户帐户?

【问题讨论】:

  • 我为文字墙道歉,但我希望我的回答能让您更深入地了解实际发生的情况。
  • 这里不需要道歉,这是一堵巨大的文字墙,我只是在阅读它。我有几个问题将附加到您的答案中。谢谢!

标签: c# database entity-framework azure entity-framework-migrations


【解决方案1】:

Migrations 和 Database Initializer CreateDatabaseIfNotExists 不一样

迁移使用数据库初始化程序MigrateDatabaseToLatestVersion,它依赖于数据库_MigrationsHistory 中的一个特殊表。

相比之下,CreateDatabaseIfNotExists 是依赖于特殊数据库表EdmMetadata 的数据库初始化程序之一。它完全按照它的暗示:创建一个包含与模型当前状态匹配的表的数据库,即为每个DbSet<T> 创建一个表,仅当数据库不存在时 .

您在此处引用的具体错误 Model compatibility cannot be checked because the database does not contain model metadata. 是由于存在 DbSet<T> 对象而发生的EdmMetadata.

有 4 个基本的数据库初始化器可用,其中 3 个在不使用迁移时使用:

  • CreateDatabaseIfNotExists
  • DropCreateDatabaseWhenModelChanges
  • DropCreateDatabaseAlways

另外请注意,第 4 个初始化器 MigrateDatabaseToLatestVersion 将允许您使用迁移即使 AutomaticMigrations 被禁用; AutomaticMigrations 有不同的用途,不直接与数据库初始化器交互。

如果您打算使用 Migrations,则应将 Database Initializer 更改为 MigrateDatabaseToLatestVersion 并忘记其他 3。如果您打算使用 Migrations,则选择 Initializer是情境性的。

  • CreateDatabaseIfNotExists 当您确定您的数据模型没有进行主动更改并且您只打算关注新部署上的数据库创建时会更合适。此初始化程序将确保您不会遇到任何意外删除数据库或实时数据的问题。
  • DropCreateDatabaseWhenModelChanges 最适合开发中,当您经常更改模型并希望能够验证对模型的这些更改时。它不适用于生产服务器,因为对模型的更改可能会无意中导致重新创建数据库。
  • DropCreateDatabaseAlways 仅适用于测试,每次运行测试时都会从头开始创建数据库。

Migrations 与这 3 个 Database Initializers 不同,因为它从不删除 数据库,而是使用 Data Motion 执行一系列Create TableDrop Table SQL 调用。

您也可以随时在包管理器控制台中使用Update-Database -Script -SourceMigration:0,无论您使用的是哪个数据库初始化程序,都可以生成完整的 SQL 脚本,该脚本可以在服务器上运行以重新创建数据库。

【讨论】:

  • Claies,这是一个很好的答案,我绝对不知道 EdmMetadata 表。我知道迁移与创建现在是不同的事情,我假设创建机制只是迁移方法的第一步。对我来说,选择“如果数据库不存在就创建数据库”方法似乎是明智的。现在让我更改我的代码以使用 MigrateDatabaseToLatestVersion,看看会发生什么,我会报告!
  • 好的,所以我已经切换到使用 MigrateDatabaseToLatestVersion(我在 DbContext 的静态构造函数中设置,可以吗?)。我必须为模型的初始状态创建迁移。然后我运行了创建数据库的 migrate.exe。我有一个 __MigrationHistory 记录,这是我的初始模型。在应用程序启动时,我仍然遇到同样的错误。一定是我错过了一些微妙的东西。
  • 您的 web.config 中是否碰巧有一个额外的连接字符串?以metadata=res ... 开头的东西?这些对于迁移实际上并不是必需的,如果它们存在于 web.config 但指向本地测试数据库,它们可能不会像实际的数据库连接字符串那样以天蓝色的方式自动更新。
  • 虽然不错,但我的配置文件中没有任何元数据的迹象。我会继续挖掘!
  • EdmMetadata 实际上已经过时了;这是一种确定自创建数据库以来 Code First 模型是否已更改的简单方法。但是,它不能用于确定用于创建数据库的模型如何与当前模型不同。这无关紧要,因为无法将数据库从一个版本迁移到下一个版本。 (整个数据库刚刚被删除并重新创建)。迁移实际上可以检测表的创建和删除顺序;如果您收到此错误,可能是 _MigrationHistory 表有问题?
【解决方案2】:

首先,非常感谢 Claies 帮助我解决了这个问题。我已经接受他的回答是正确的,因为最终是他的回答和一些额外的阅读使我找到了解决方案。

回答实际帖子问题“当 SQL Azure 中不存在数据库时,我是否需要先迁移 EF 代码?”如果您禁用了自动迁移,答案是肯定的。但还有一点需要注意:

这个特定问题的 Azure 方面实际上与我的情况无关。我的问题有两个:

  1. 生成的迁移与目标模型不同步。我是什么意思?我的意思是,我是从本地数据库生成迁移脚本,而本地数据库本身与本地代码库不同步,本地代码库创建了不正确的迁移。这可以通过比较 __MigrationHistory 中模型文本的前几行来看出。参考这个有用的post 有助于提高这种认识,该post 解释了它是如何工作的。

  2. 更尴尬的是(我相信我们都做到了)是我的网站本身的章鱼部署(使用 Octopack)不知何故忽略了包含 Web.Config 文件。据我所知,这可能是在我将转换扩展安装到 Visual Studio 之后发生的。在我的 nuget 包中,我可以看到有一个 web.config.transform 文件,但没有 web.config。基本上这意味着当应用程序启动时,它没有配置文件可以转向,根本没有连接字符串。但这导致了轻微的误导性错误

无法检查模型兼容性,因为数据库没有 包含模型元数据。

虽然它应该说的是,没有连接字符串你这个白痴。 希望这有助于人们在阅读 Claies 回答和博客文章后更好地理解这个过程。不过,首先,检查你有一个 web.config 文件,并且它里面有一个连接字符串......

【讨论】:

    猜你喜欢
    • 2016-05-26
    • 2013-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多