【问题标题】:Why does Entity Framework's EF Migrations Add-Migration step require a database connection string?为什么实体框架的 EF 迁移添加迁移步骤需要数据库连接字符串?
【发布时间】:2012-05-29 14:33:38
【问题描述】:

我正在尝试使用和理解 EF 迁移(使用 EF 4.3.1,代码优先)。为了构建新的更改,我必须使用这样的命令:

Add-Migration MyMigration
   -ConnectionString "Data Source=.;Initial Catalog=mydb;" 
   -ConnectionProviderName "System.Data.SqlClient"
   -StartUpProjectName MyWebsite 
   -ProjectName MyEF.Migrations

为什么添加迁移需要连接字符串数据? Update-Database 需要一个,这是有道理的。但是 Add-Migration 不具备 DbContext 和 Configuration 所需的一切吗?

给它一个数据库不是简单的奇迹,给它一个数据库是非常令人困惑的,因为我们有一个“多租户”的东西,其中所需的数据库是灵活的,并且可能会随着请求的变化而变化,更不用说在静态编译时了。因此,如果 Add-Migration 实际上正在使用该数据库进行任何操作,那么我们就有问题了。

更新:我们放弃了 EF 迁移并改用 Fluent Migrator,并且很高兴。它的速度要快得多,甚至算上我们必须写两次(一次用于 EF 对象,一次用于迁移)的事实,而且它没有这个问题中讨论的问题。

【问题讨论】:

    标签: entity-framework-4 entity-framework-4.3 entity-framework-migrations


    【解决方案1】:

    Add-Migration 检查数据库是否存在并与__MigrationHistory 表交互。正如@Anders Abel 提到的,它用于调查待处理的迁移,也用于选择以前的模型以实际发现发生了什么变化 - 如果您将显式迁移添加到启用自动迁移的解决方案中,这一点尤其重要。

    【讨论】:

    • 它应该能够从 Designer.cs 中迁移的 Target 属性中获取模型以进行比较。
    • 而且我不希望它知道待处理的迁移,因为它们特定于一个随机数据库恰好处于的任何状态(并且不同于我或我的团队正在使用的其他状态).. . ;( 恐怕我对 EF Migrations 的设计越来越失望了——似乎它试图做的太多了。
    • 拥有多少数据库并不重要。在开发中,每个开发人员都应该使用一个并准备基于代码的迁移。在部署期间,您应该将所有数据库移动到相同的状态。在团队开发中处理迁移很棘手,如果两个开发人员同时对模型进行更改,则需要尽快通过迁移提交模型更改,并进行一些手动合并。移民是满州的——他们给发展带来了新的挑战。如果您不喜欢它,请不要使用它们并手动处理数据库更新。
    • 我发布了一个类似的问题......基于代码的迁移要求数据库存在或保持最新是没有意义的! :(stackoverflow.com/questions/11204900/…
    • @Danny:这是有道理的,因为数据库可以包含您的代码中没有的迁移...
    【解决方案2】:

    我在阅读您的问题时很好奇,所以我启动了一个 Sql Server Profiler 来查看运行 add-migration 时发生了什么。它确实连接到数据库并访问数据库以检查__MigrationHistory 表。

    在尝试创建第二个基于代码的迁移而不运行第一个迁移时产生的错误消息也显示了这一点:

    无法生成显式迁移,因为以下原因 显式迁移待定:[201205291928386_foo]。应用 在尝试生成新迁移之前等待显式迁移 显式迁移。

    我认为迁移引擎使用数据库中的序列化模型来计算应该在新迁移中包含哪些迁移步骤。

    据我了解,数据库只是作为代码生成的助手。只要您使用的所有各种数据库都与代码中的模型兼容,这对您来说应该不是问题。

    编辑

    正如@Ladislav Mrnka 指出的那样,如果混合使用基于代码的迁移和自动迁移,则需要检查数据库。当你搭建一个新的迁移时,它应该包括自上次迁移以来你的模型中发生的任何变化。如果您使用的是自动迁移,则不会在代码中跟踪这些迁移。在计算要包含在迁移中的更改时,使用上次运行的迁移作为基础。检查的唯一方法是数据库 - 因为可能会打开自动迁移。

    如果您只使用基于代码的迁移(我认为这是保持控制的唯一选择),那么该数据库可以被视为只是一个代码生成帮助。只要确保您连接到的所有数据库中的模型兼容性,一切都应该正常。

    【讨论】:

    • 如果我将AutomaticMigrationsEnabled 设置为false,这个分析会有什么变化? (如果我不再需要指定数据库,我想我可以生活在一个没有自动迁移的世界中。)
    • 不幸的是,我认为分析不会改变。 EF 无法知道您是否一直禁用自动迁移,或者您到目前为止是否一直在使用它并在运行之前将其禁用。
    • 应该有办法告诉它!以这种方式完全取消使用迁移的能力,绝对是 0 的好处是没有意义的 :(
    • 我发布了类似的内容:stackoverflow.com/questions/11204900/…
    【解决方案3】:

    我从 2014 年 3 月开始观看 Rowan Miller 的这段视频:Migrations - Under the Hood

    在视频中,Rowan 解释说Add-Migration 命令执行多个步骤,其中包括一个名为EdmModelDiffer 的组件。 EdmModelDiffer 将当前模型与上次迁移的先前模型(嵌入在上次迁移的 resx 文件中)进行比较,然后计算数据库所需的更改。

    所以EdmModelDiffer 组件需要数据库连接。

    视频中描述的步骤是:

    1. 从代码构建当前模型
    2. 从上次迁移中获取以前的模型(作为快照存储在 resx 文件中)
    3. 计算所需的数据库更改(由EdmModelDiffer 完成)
    4. 生成了新的迁移文件

    理论上,可以假设将当前模型与上次迁移的模型进行比较就足以生成新的迁移。 但与此同时,其他人也可以在数据库中执行更改。这可能就是为什么还要检查数据库的原因。 如果不这样做,生成的迁移文件就不需要是正确的。


    也可以看看第二个视频Migrations - Team Environments

    【讨论】:

      【解决方案4】:

      OP 写道:

      但是 Add-Migration 并没有从 DbContext 获得所需的一切 和配置?

      不 - 正如其他人在此处提到的那样,手动迁移代码的设计器部分(由 add-migration 创建)包含您的数据库架构的快照。

      也就是说,您使用连接字符串等的事实非常奇怪。 EF 通常从您的 DbContext 类和 Web.Config 中暗示它。在我有一个数据库和一个 DbContext 的项目中,我创建了一个配置类并添加了一个手动迁移:

      add-migration
      

      我不必传递任何其他命令行参数。那是在 EF 4.3.1 中 - 也许您使用的是 CTP 或某些旧版本,或者只是误解了文档?

      如果我有多个 DB 或 DbContexts,那么我有多个 Configuration 类并使用例如:

      add-migration -conf Log
      

      它使用我的配置类和 Web.config 中的相关连接字符串为该数据库/DbContext 添加手动迁移。

      这是一个用于存储日志(与主数据库分开)的简单 DbContext 的较长代码示例:

      namespace MyProj.Models.Log
      {
          public class LogDb : DbContext
          {
              public DbSet<LogLine> LogLines { get; set; }
              public DbSet<LogTag> LogTags { get; set; }
      
      
              protected override void OnModelCreating(DbModelBuilder modelBuilder)
              {
                  modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
              }
          }
      
          public LogDb()
      #if DEPLOYDB
               : base("LogDeploy")
      #else
               : base()
      #endif
           {
           }
      }
      
      namespace MyProj.Migrations
      {
          internal sealed class Log : DbMigrationsConfiguration<LogDb>
          {
              public Log()
              {
                  AutomaticMigrationsEnabled = true;
              }
          }
      }
      

      在 Web.Config 中:

      <add name="LogDb" connectionString="Initial Catalog=Log;Data Source=.\SqlExpress;Integrated Security=SSPI;MultipleActiveResultSets=true" providerName="System.Data.SqlClient" />
      <add name="LogDeploy" connectionString="Initial Catalog=Log;Data Source=00.00.000.00,12345;User ID=sql;Password=xxx;Network Library=DBMSSOCN" providerName="System.Data.SqlClient" />
      

      所以在这个例子中,我有多个数据库,多个 DbContext。 LogDb 根据是否在编译时定义了“DBDEPLOY”,在 Web.Config 中使用不同的连接字符串;如果是,它使用“LogDeploy”。如果不是,它使用默认值 - 与类同名的连接字符串“LogDb”。这使我可以轻松地将数据库更改从本地机器部署到服务器,方法是切换我的项目配置,在 SQL 数据库机器上打开一个端口,然后运行:

      > update-database -conf Log
      

      在包管理器控制台中。

      【讨论】:

        猜你喜欢
        • 2014-07-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-24
        • 1970-01-01
        • 2012-08-17
        • 1970-01-01
        相关资源
        最近更新 更多