为了能够解决您的问题,您应该了解 EF 如何处理连接字符串以及迁移的工作原理。
EF 如何处理连接字符串:通常您的DbContext 有一个无参数构造函数,它使用硬编码的连接字符串名称调用其基类构造函数。您的项目 app.config 或 web.config 文件应包含一个 connectionStrings 部分,该部分定义了具有该名称的连接字符串。 这是您的项目中使用的默认连接字符串,当您没有为包管理器控制台命令显式提供连接字符串参数时。
一些带有连接字符串名称MyConnectionStringName的示例代码:
public class MyDbContext : DbContext
{
public MyDbContext() : base("MyConnectionStringName") { ... }
...
}
在您的.config 文件中:
<configuration>
...
<connectionStrings>
<add name="MyConnectionStringName" connectionString="..." />
</connectionStrings>
</configuration>
如果您不使用该方法,您仍然可以在包管理器控制台中手动将正确的连接字符串作为参数提供给 Update-Database,如下所示:
Update-Database -ConnectionString <your connection string here> -ConnectionProviderName System.Data.SqlClient
您还可以使用您在.config 文件中定义的任何连接字符串名称:
Update-Database -ConnectionStringName MyConnectionStringName
现在关于迁移的工作原理:迁移是代码文件。每次运行Add-Migration 时,都会生成/更新一个代码文件,通常位于项目内名为Migrations 的文件夹中。迁移文件的名称由其生成时间戳和运行Add-Migration 时使用的名称组成。您可以检查这些文件的内容并查看运行Add-Migration 的效果。您还可以在生成它们后对其进行修改,然后添加自己的代码,尽管目前您不需要这样做。
迁移是增量的。您从Initial 迁移开始,每次更改模型代码时都会生成一个新的迁移文件。该数据库包含一个名为 __MigrationsHistory 的表,用于跟踪您的数据库中运行了哪些迁移。
每个迁移都有一个方法Up 和一个方法Down。当你运行Update-Database 时,总是有两个隐式参数:SourceMigration 和TargetMigration。 EF 以增量方式应用 SourceMigration 和 TargetMigration 之间所有迁移的 Up 方法(如果您正在降级数据库,则使用 Down 方法)。未指定SourceMigration 和TargetMigration 参数时的默认情况是SourceMigration 是应用于数据库的最后一个迁移,TargetMigration 是最后一个未决迁移。 EF 通过查询项目默认数据库的__MigrationsHistory 表来确定这些参数,因此如果该数据库处于不一致的状态,则可能会错误地生成迁移。我认为这是导致您的问题的原因。
因此,每次运行 Update-Database 时,EF 都会查看 __MigrationsHistory 表以了解必须运行哪些迁移,具体取决于数据库的状态,并且在执行迁移的 SQL 后,会在其中插入一条新记录每个应用迁移的表。
似乎在某些时候您的数据库__MigrationsHistory 内容搞砸了。当运行 Update-Database 和 Add-Migrations 时没有遵循正确的顺序并使用 -force 参数时会发生这种情况。
解决问题的建议:从头开始:删除数据库,删除迁移文件,使用Add-Migration Initial 生成新的干净Initial 迁移,使用@987654364 仅运行一次@。从那时起,每次更改模型代码时,您都会使用 Add Migration YourNewMigrationName 生成一个新的增量迁移,每次使用不同的名称,并通过运行一次 Update-Database 来应用新的迁移。
注意:除了增量迁移之外,如果您对迁移的工作方式有足够的了解,您也可以只使用一个 Initial 迁移,并在模型代码更改时通过执行 Add-Migrations Initial -force 来更新它。 -force 参数确保不会生成新的迁移文件,而是覆盖现有的Initial 迁移文件。这种方法在开发阶段很方便,但在生产中通常不是一个好方法,因为您可能希望每次部署新版本的代码时都以增量方式运行数据库更新(您可能无法删除数据库并重新创建它,您还需要维护您的数据并确保在更新数据库时不会丢失数据。
迁移是由 EF 生成的用于创建和更新数据库的代码文件。当您运行Update-Database 时,迁移将转换为针对您的数据库执行的 SQL。如果您想查看为特定迁移生成的确切 SQL,可以运行 Update-Database -Script -SourceMigration SomeMigration -TargetMigration SomeOtherMigration。该命令不会修改数据库,只是生成并显示将在真正的Update-Database 执行中应用的 SQL。
更多关于生成和运行迁移的信息可以在here找到。
祝你好运!
更新:此答案适用于 EF6。请注意,在使用 EF Core 的 EF6 之后,情况发生了一些变化。此答案中解释的基本概念是相同的,但包管理器控制台命令发生了变化,EF 处理数据库上下文快照和迁移的方式也发生了变化。