26

我正在尝试使用和理解 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 和配置中获得了它需要的一切吗?

给它一个数据库,这不仅仅是空想,它非常令人困惑,因为我们有一个“多租户”的东西,其中所需的数据库是灵活的,并且可能会因请求而异,更不用说在静态编译时。因此,如果Add-Migration实际上将该数据库用于任何事情,我们就会遇到问题。

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

4

4 回答 4

13

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

于 2012-05-29T19:35:15.630 回答
10

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

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

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

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

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

编辑

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

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

于 2012-05-29T19:32:46.777 回答
1

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

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

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

视频中描述的步骤是:

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

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


还可以看一下名为Migrations - Team Environments的第二个视频

于 2015-12-07T13:24:41.223 回答
0

OP写道:

但是 Add-Migration 不是从 DbContext 和配置中获得了它需要的一切吗?

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

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

add-migration

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

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

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

在包管理器控制台中。

于 2012-09-11T21:34:41.143 回答