我正在尝试使用和了解EF迁移(使用EF 4.3.1,Code First)。为了支持一个新的变化,我必须使用这样的命令:
Add-Migration MyMigration
-ConnectionString "Data Source=.;Initial Catalog=mydb;"
-ConnectionProviderName "System.Data.SqlClient"
-StartUpProjectName MyWebsite
-ProjectName MyEF.Migrations
为什么Add-Migration需要连接字符串数据? Update-Database
需要一个,这是有道理的。但是,Add-Migration是否具有DbContext和Configuration所需的一切?
这不仅仅是空闲的奇迹,给它一个数据库是非常困惑的,因为我们有一个“多租户”的东西,所需的数据库是灵活的,可能会从请求变为请求,更不用说在静态编译时。因此,如果Add-Migration
实际上正在使用该数据库,我们就会遇到问题。
更新:我们放弃了EF迁移并改为使用Fluent Migrator,并且很高兴。它更快,更快,甚至计算我们必须写两次东西(一次用于EF对象,一次用于迁移),并且它没有在这个问题中讨论过的问题。
答案 0 :(得分:12)
Add-Migration
检查数据库的存在并与__MigrationHistory
表进行交互。正如@Anders Abel提到的,它用于调查待定迁移以及选择以前的模型以实际查找已更改的内容 - 如果您将显式迁移添加到启用了自动迁移的解决方案中,这一点尤其重要。
答案 1 :(得分:9)
我在阅读你的问题时很好奇,所以我启动了一个Sql Server Profiler来查看运行add-migration时发生了什么。它确实连接到数据库并访问数据库以检查__MigrationHistory
表。
尝试在不运行第一个的情况下创建第二个基于代码的迁移时产生的错误消息也显示了这一点:
无法生成显式迁移,因为以下内容 显式迁移正在等待:[201205291928386_foo]。适用 在尝试生成新的之前暂挂显式迁移 显式迁移。
我认为迁移引擎使用数据库中的序列化模型来计算新迁移中应包含哪些迁移步骤。
据我所知,数据库仅用作代码生成的帮助程序。只要您使用的所有各种数据库都与代码中的模型兼容,这对您来说就不是问题。
正如@Ladislav先生所指出的,如果混合基于代码和自动迁移,则需要检查数据库。当您构建新迁移时,它应该包括自上次迁移以来模型中已更改的所有内容。如果您使用自动迁移,则不会在代码中跟踪这些迁移。在计算要在迁移中包含的更改时,上次运行迁移将用作基础。检查它的唯一方法是数据库 - 因为可能会启用自动迁移。
如果您只运行基于代码的迁移(我认为这是保持控制的唯一选择),那么该数据库可以被视为代码生成帮助。只要在您连接的所有数据库中确保了模型兼容性,一切都应该有效。
答案 2 :(得分:0)
但是Add-Migration没有DbContext所需的一切 和配置?
否 - 正如其他人在此处提到的,手动迁移代码的Designer部分(由add-migration
创建的内容)包含数据库架构的快照。
那就是说,你使用连接字符串等的事实很奇怪。 EF通常从您的DbContext类和Web.Config中暗示它。在我有一个数据库和一个DbContext的项目中,我创建了一个Configuration类并添加了一个手动迁移:
add-migration
我不必传递任何其他命令行参数。这是在EF 4.3.1中 - 也许您使用的是CTP或某些旧版本,或者只是误解了文档?
如果我有多个DB或DbContexts,那么我有多个配置类并使用例如:
add-migration -conf Log
使用我在Web.config中的Configuration类和相关连接字符串为该数据库/ 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" />
所以在这个例子中,我有多个数据库,多个DbContexts。 LogDb在Web.Config中使用不同的连接字符串,具体取决于在编译时是否定义了“DBDEPLOY”;如果是,它使用“LogDeploy”。如果不是,则使用默认值 - 与类名称相同的连接字符串“LogDb”。这使我可以通过切换我的项目配置,打开SQL数据库计算机上的端口并运行以下命令,从本地计算机轻松地将数据库更改部署到服务器:
> update-database -conf Log
在程序包管理器控制台中。
答案 3 :(得分:0)
我观看了Rowan Miller从2014年3月开始的这段视频:Migrations - Under the Hood
在视频中,Rowan解释说Add-Migration
命令执行了几个步骤,其中包括一个名为EdmModelDiffer
的组件。
EdmModelDiffer
将当前模型与上次迁移中的先前模型(嵌入在先前迁移的resx文件中)进行比较,然后计算对数据库所需的更改。
因此EdmModelDiffer
组件需要数据库连接。
视频中描述的步骤为:
EdmModelDiffer
完成)理论上可以假定将当前模型与上次迁移的模型进行比较以生成新迁移就足够了。 但与此同时,其他人也可以对数据库进行更改。这可能是对数据库进行检查的原因。 如果不这样做,生成的迁移文件就不需要是正确的。
另请参阅第二个名为Migrations - Team Environments