【问题标题】:EF Core Migration error: Database 'MyDatabaseName' already exists. Choose a different database nameEF Core 迁移错误:数据库“MyDatabaseName”已存在。选择不同的数据库名称
【发布时间】:2018-06-22 05:08:31
【问题描述】:

我在带有 SQL Server 2017 Web 版的 Windows Server 2016 上运行带有 EF Core 2.1 应用程序的 ASP.NET Core 2.1。

Startup.cs 中的public void Configure(IApplicationBuilder app, ... 方法结束时,我调用context.Database.Migrate();。这适用于迁移。
一切正常。

现在我在 SQL Server 2016 的开发环境中备份数据库,将 MyDatabaseName .bak 文件移动到服务器并在服务器上恢复数据库 MyDatabaseName 并重新启动 IIS 站点。
当我启动应用程序(打开浏览器)时,出现以下错误:

应用程序启动异常:System.Data.SqlClient.SqlException (0x80131904): 数据库 'MyDatabaseName' 已经存在。选择一个 不同的数据库名称。

在线:context.Database.Migrate();。 完整的错误在底部。

如果我将MyDatabaseName 更改为MyDatabaseNameX(不存在),则创建数据库,应用所有迁移,我可以重置 IIS,启动应用程序。如果我恢复数据库,我会收到错误already exists

相同的应用程序(完全相同的 dll)在开发和生产环境中运行应用程序。这也意味着数据库结构是相同的。

我需要在生产环境中恢复数据库。我只是不确定为什么context.Database.Migrate() 会抛出错误?

完全错误:

应用程序启动异常:System.Data.SqlClient.SqlException (0x80131904): 数据库 'MyDatabaseName' 已经存在。选择一个 不同的数据库名称。在 System.Data.SqlClient.SqlConnection.OnError(SqlException 异常, Boolean breakConnection, Action1 wrapCloseInAction) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) 在 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler、SqlDataReader 数据流、 BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean & dataReady) 在 System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(字符串 方法名,布尔异步,Int32 超时,布尔异步写入)在 System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource1 completion, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite, String methodName) at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary2 参数值)在 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteNonQuery(IRelationalConnection 连接,IReadOnlyDictionary2 parameterValues) at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary2 参数值)在 Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands,IRelationalConnection 连接)在 Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.Create() 在 Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(字符串 目标迁移)在 Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.Migrate(DatabaseFacade databaseFacade) 在 MyProject.Startup.Configure(IApplicationBuilder app, AppUserManager userManager, IServiceProvider serviceProvider) 在 C:\GitLab-Runner\builds\7cab42e4\0\web\MyProject\Startup.cs:line 582 --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 Microsoft.AspNetCore.Hosting.ConventionBasedStartup.Configure(IApplicationBuilder 应用程序)在 Microsoft.AspNetCore.Server.IISIntegration.IISSetupFilter.c__DisplayClass4_0.b__0(IApplicationBuilder 应用程序)在 Microsoft.AspNetCore.Hosting.Internal.AutoRequestServicesStartupFilter.c__DisplayClass0_0.b__0(IApplicationBuilder 建设者)在 Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication() ClientConnectionId:7f6b84a3-e0ea-42c7-947d-a9cafdaffbfa 错误 Number:1801,State:3,Class:16 托管环境:Production Content 根路径:C:\WWW\MyProject 现在监听:http://127.0.0.1:24830 申请开始。按 Ctrl+C 关闭。申请是 正在关闭...

【问题讨论】:

  • 错误很简单。 context.Database.Migrate(); 创建数据库。
  • 为什么它可以在开发环境中工作?以及为什么我输入MyDatabaseNameX 然后重新启动IIS 会起作用。当我运行应用程序时,它应该会引发相同的错误,但不会。仅在还原时使用。当我开发时,每次调试时都会进行此调用,但不会引发错误。
  • 能不能先删除__efmigrationhistory的表再拿回来试试
  • 连接字符串中使用的帐户是否可以访问恢复的数据库?

标签: entity-framework-core entity-framework-core-migrations entity-framework-core-2.1


【解决方案1】:

这是一个讨厌的。数据库确实存在(我确实恢复了它),但问题是数据库的备份所有者也被转移了。
本地主机上的所有者用户在服务器上不存在。所以迁移没有找到数据库(因为它没有访问权限)所以它尝试创建一个新的。

【讨论】:

    【解决方案2】:

    在开始讨论可能的修复之前,我们需要了解一件重要的事情:迁移模式是确保您正在处理的所有数据库(并且您将用于连接您的应用) 将在任何给定环境(测试、阶段、生产、DR 等)中具有一致且最新的结构;如果您选择使用它,您能做的最好的事情就是坚持模式最佳实践,并确保在需要时调用Migrate() 方法。

    也就是说,您可能仍希望在第一次运行时仅使用 Migrate() 方法来创建数据库,而无需以编程方式(自动)跟踪任何进一步的迁移。如果这就是您所生活的场景,那么您可以做的最好的事情就是将 Migrate() 方法包装在一个条件块中,如下所示:

    if (!dbContext.Database.GetService<IRelationalDatabaseCreator>().Exists())
    {
        var host = BuildWebHost(args);
        using (var scope = host.Services.CreateScope())
        {
            var dbContext = scope.ServiceProvider.GetService<ApplicationDbContext>();
            var roleManager = scope.ServiceProvider.GetService<RoleManager<IdentityRole>>();
            var userManager = scope.ServiceProvider.GetService<UserManager<ApplicationUser>>();
    
            // Create the Db if it doesn't exist and applies any pending migration.
            dbContext.Database.Migrate();
    
            // Seed the Db
            DbSeeder.Seed(dbContext, roleManager, userManager);
        }
        host.Run();
    }
    

    这样,您将确保 Migrate() 方法仅在数据库尚不存在时以编程方式执行:这对于测试环境来说是完美的,您每次都可以删除并重新创建数据库而不必担心关于丢失实际数据,和/或您更喜欢手动更新数据库的任何其他上下文 - 例如使用dotnet ef powershell 命令。这对性能有好处,也可以避免 Migrate() 方法中的 SqlException,因为它只会在没有数据库开始时运行,从而防止找到错误或过时的迁移数据的机会。

    如果您对 Exists() 方法实际上在幕后做了什么感到好奇,您可以通过查看 EF Core’s official GitHub repository 中的 SqlServer.Storage/Internal/SqlServerDatabaseCreator.cs 类中的魔术 - 只是尝试打开连接并捕获 SqlException 并返回 false 或返回 true。可能不是您希望在那里找到的最好的东西,但总比没有好(至少它可以完成工作)。

    如果您需要更多信息,请查看the blog post that I wrote on such issue

    【讨论】:

      【解决方案3】:

      一种可能是数据库是由其他东西/早期迁移创建的。

      如果数据库在列表中(不应该),您可以通过查看Sql server management studio 来验证是否是这种情况。然后尝试创建具有相同名称的数据库。如果你再次收到错误,那是因为它已经被创建了。

      至于解决方案,您可以简单地等待数据库存在,以便再次迁移,但这并不总是可行的。 另一种方法是尝试捕获此异常并添加重试机制。

      try 
      {
          // migrate
      }
      catch (SqlException exception) when (exception.Number == 1801)
      {
          // retry
      }
      

      【讨论】:

        【解决方案4】:

        IIS APPPOLL用户添加到您的数据库MyDatabaseName的用户列表中@

        【讨论】:

          猜你喜欢
          • 2016-11-18
          • 2018-06-19
          • 2019-08-03
          • 1970-01-01
          • 2015-07-20
          • 1970-01-01
          • 2022-09-29
          • 1970-01-01
          • 2020-01-25
          相关资源
          最近更新 更多