【问题标题】:EntityFramework 6 Migrations for both existing and new databases?EntityFramework 6 现有数据库和新数据库的迁移?
【发布时间】:2013-11-07 09:07:31
【问题描述】:

在我们的软件中,我们有一个拥有现有数据库的客户群。目前通过 EntitySpaces 访问数据库,但我们希望切换到 EntityFramework (v6),因为不再支持 EntitySpaces。我们还想利用迁移功能。自动迁移被禁用,因为我们只想允许数据库迁移到管理员用户。

我们从现有数据库生成了 EF 模型。这一切都很好,但我们遇到的真正问题是,以编程方式区分与模型匹配但尚未转换为 EF 的现有数据库(缺少 MigrationsHistory 表)和空/新数据库。转换现有数据库适用于空迁移,但对于新数据库,我们还需要包含完整模型的迁移。在迁移链中进行初始迁移总是与现有数据库发生冲突。当然,我们可以使用外部 SQL 脚本或 ADO 命令创建解决方法,创建并填充 MigrationsHistory 表。但这是我们想要避免的,因为我们的一些客户使用 MsSql 数据库,一些使用 Oracle。所以我们真的很想保留 EF 提供的抽象层。

有没有办法让 EF 通过基于代码的迁移来处理现有数据库和新数据库,而无需回退到非 EF 变通办法?

【问题讨论】:

  • 有点离题,但 FluentMigrator 的 Schema.Exists 表达式似乎是支持此用例所需的全部内容。我发现 EF 似乎没有此功能令人沮丧。

标签: c# entity-framework migration entity-framework-6 entityspaces


【解决方案1】:

我最初的建议是捕获 CreateTable 引发的异常,但事实证明这是在不同的地方执行的,因此不能将其捕获在异常中。

最简单的方法是使用 Seed 方法来创建您的初始数据库(如果它不存在)。为此...

  1. 从空白数据库开始,添加 Initial Create 迁移并抓取生成的 SQL

    Add-Migration InitialCreate
    Update-Database -Script
    
  2. 保存此脚本。您可以将其添加到资源、静态文件中,或者如果您真的需要,甚至可以将其内嵌在代码中,这取决于您。

  3. 从 InitialCreate 迁移中删除所有代码(留下空白的 Up() 和 Down() 函数)。这将允许您运行空迁移,从而生成 MigrationHistory 表。

  4. 在您的 Migration 配置类中,您可以使用 context.Database.SqlQuerycontext.Database.ExecuteSqlCommand 动态查询和执行 SQL。测试您的主表是否存在,如果不存在,则执行上面生成的脚本。

这不是很整洁,但实现起来很简单。好好测试一下,因为 Seed 方法在每次迁移运行后运行,而不仅仅是最初的迁移。这就是为什么您需要在执行任何操作之前测试主表是否存在。

更复杂的方法是为迁移编写“CreateTableIfNotExists”方法,但这将涉及使用反射来调用 DbMigration 类中的内部方法。

【讨论】:

  • 感谢您的快速回复,理查德。尝试了您的方法,因为它看起来与我正在寻找的完全一样。问题是,SQL 的实际执行发生在 EF 内其他地方的 up/down 方法之外。因此,在迁移代码中捕获 SqlExceptions 将无济于事。甚至试图通过 Sql(...) 方法执行一个虚假的 SQL 命令。因此,必须在迁移之外,围绕 Update(...) 方法捕获异常。但是您无法直接访问数据库。回到起点。
  • 嗯,没有意识到这一点。查看源代码,您应该能够创建自定义迁移操作,但这并不容易。迁移过程的内部都是“内部的”,但您可以使用反射来创建“CreateTableIfNotExists”方法。不过,我对此无能为力!
  • 用新建议更新了答案。
  • 感谢您的更新。尽管您的建议最终会奏效,但我最终决定退回到简单的 sql 脚本。虽然我需要为每个 dbms 单独编写一个脚本,但仍然没有那么痛苦……我将向 EF 团队建议某种迁移前和迁移后挂钩。干杯伙伴。
猜你喜欢
  • 2017-11-22
  • 1970-01-01
  • 2011-07-29
  • 1970-01-01
  • 1970-01-01
  • 2018-09-27
  • 2015-07-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多