EF核心迁移错误:数据库“ MyDatabaseName”已存在。选择其他数据库名称

时间:2018-06-22 05:08:32

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

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

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

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

  

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

in line:context.Database.Migrate();。 完全错误在底部。

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

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

我需要恢复生产数据库。我只是不确定为什么context.Database.Migrate()会引发错误?

完整错误:

  

应用程序启动异常:System.Data.SqlClient.SqlException   (0x80131904):数据库“ MyDatabaseName”已存在。选择一个   不同的数据库名称。在   System.Data.SqlClient.SqlConnection.OnError(SqlException异常,   布尔值breakConnection,操作为1 wrapCloseInAction) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action 1 wrapCloseInAction),位于   System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject   stateObj,布尔值调用者HasConnectionLock,布尔值asyncClose)   System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,   SqlCommand cmdHandler,SqlDataReader dataStream,   BulkCopySimpleResultSet bulkCopyHandler,TdsParserStateObject   stateObj,Boolean&dataReady)   System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(字符串   methodName,布尔异步,Int32超时,布尔asyncWrite)位于   System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource 1 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, IReadOnlyDictionary 2   parameterValues)   Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteNonQuery(IRelationalConnection   连接,位于IReadOnlyDictionary 2 parameterValues) at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary 2 parameterValues)   Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1   migrationCommands,IRelationalConnection连接)在   Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.Create()   在   Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(字符串   targetMigration)   Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.Migrate(DatabaseFacade   MyProject.Startup.Configure(IApplicationBuilder)上的databaseFacade   app,AppUserManager userManager,IServiceProvider serviceProvider)中   C:\ GitLab-Runner \ builds \ 7cab42e4 \ 0 \ web \ MyProject \ Startup.cs:第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错误   编号:1801,状态:3,类别:16托管环境:生产内容   根路径:C:\ WWW \ MyProject现在正在监听:http://127.0.0.1:24830   应用程序已启动。按Ctrl + C关闭。申请是   关闭...

4 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

在开始讨论可能的修复之前,我们需要了解一件重要的事情:迁移模式是确保正在使用的所有数据库的一种极好的方法(并且您将使用它来连接应用程序与)在任何给定的环境(测试,阶段,生产,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命令)。这不仅对性能有好处,而且还避免了SqlException方法中的Migrate(),因为它只会在没有数据库开始时运行,从而避免了发现错误或过时的迁移数据的机会。 / p>

如果您对Exists()方法在幕后的实际用途感到好奇,则可以通过查看SqlServer.Storage/Internal/SqlServerDatabaseCreator.csEF Core’s official GitHub repository类中的来轻松地检查出来:将会看到并没有真正的魔力–只是尝试打开连接并捕获SqlException并返回false或返回true。可能不是您希望在那里找到的最好的东西,但总比没有好(至少它能做到)。

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

答案 2 :(得分:0)

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

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

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

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

答案 3 :(得分:0)

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