使用Code-First更新数据库时出错:“数据库中已经有一个名为'something'的对象。”

时间:2016-11-15 09:23:22

标签: vb.net asp.net-web-api visual-studio-2015 sql-server-2012 ef-code-first

我正在使用Visual Studio 2015中的Code-First进行数据库迁移。在此过程中,我已完成迁移步骤,直到添加迁移。

添加迁移后,我添加了这行代码

Database.SetInitializer(New MigrateDatabaseToLatestVersion(Of DbContext1, Migrations.Configuration))

在我的DbContext构造函数中设置Database Initializer,因为我之前错过了这一步。之后,我执行了

"Add-Migration initial -Force"
在程序包管理器控制台中

因为我担心在添加迁移过程中需要此部分。然后,我直接执行

"Update-Database"

问题是在我这样做之后,出现错误

  

此操作需要连接到“master”数据库。无法创建与“主”数据库的连接,因为已打开原始数据库连接并且已从连接字符串中删除凭据。提供未打开的连接。

ADDED

重新启动计算机后,执行“更新数据库”时,上述错误不再出现。相反,又出现了另一个错误:

  

数据库中已经有一个名为“something”的对象。

我看到了一个建议执行

的答案帖子
Add-Migration Initial -IgnoreChanges

接着是

Update-Database -verbose

我已经尝试了两种,但它仍然显示相同的错误。

1 个答案:

答案 0 :(得分:9)

为了能够解决您的问题,您应该了解EF如何处理连接字符串以及迁移的工作方式。

EF如何处理连接字符串:通常,您的DbContext具有无参数构造函数,该构造函数使用硬编码的连接字符串名称调用其基类构造函数。您的项目app.configweb.config文件应包含connectionStrings部分,该部分定义具有该名称的连接字符串。 当您未明确向Package Manager控制台命令提供连接字符串参数时,这是项目中使用的默认连接字符串

一些带有连接字符串名称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时,总会有两个隐式参数:SourceMigrationTargetMigration。如果您要降级数据库,EF会逐步应用UpSourceMigration之间所有迁移的TargetMigration方法(或Down方法)。您未指定SourceMigrationTargetMigration参数的默认方案是SourceMigration是应用于数据库的最后一次迁移,而TargetMigration是最后一次迁移待定的。 EF通过查询项目的默认数据库的__MigrationsHistory表来确定这些参数,因此如果该数据库不处于一致状态,则可能会错误地生成迁移。我认为这是造成问题的原因。

因此,每次运行Update-Database EF查看__MigrationsHistory表以了解必须运行哪些迁移,具体取决于数据库的状态,并在执行迁移的SQL后执行新记录在每个应用的迁移中插入该表。

似乎在某些时候你的数据库__MigrationsHistory内容搞砸了。在没有遵循正确的顺序并使用Update-Database参数的情况下运行Add-Migrations-force时会发生这种情况。

我的解决问题的建议:从头开始:删除数据库,删除迁移文件,使用Initial生成新的干净Add-Migration Initial迁移,仅运行它一次使用Update-Database。从那时起,每次更改模型代码时,都会使用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

祝你好运!