EF Core Migration error: Database 'MyDatabaseName' already exists. Choose a different database name
EF Core Migration error: Database 'MyDatabaseName' already exists. Choose a different database name
我是 运行 ASP.NET Core 2.1 和 EF Core 2.1 应用程序,在 Windows Server 2016 和 SQL Server 2017 Web 版上。
在 Startup.cs
中的 public void Configure(IApplicationBuilder app, ...
方法结束时,我调用了 context.Database.Migrate();
。这适用于迁移。
一切正常。
现在我在 SQL Server 2016 的开发环境中备份数据库,将 MyDatabaseName
.bak
文件移动到服务器并在服务器上恢复数据库 MyDatabaseName
并重新启动 IIS 站点.
当我启动应用程序(打开浏览器)时出现以下错误:
Application startup exception: System.Data.SqlClient.SqlException
(0x80131904): Database 'MyDatabaseName' already exists. Choose a
different database name.
行内:context.Database.Migrate();
。
完整错误在底部。
如果我将 MyDatabaseName
更改为 MyDatabaseNameX
(不存在),则创建数据库,应用所有迁移,我可以重置 IIS,启动应用程序。如果我恢复数据库,我会收到错误 already exists
.
相同的应用程序(完全相同的dll)在开发和生产环境中运行应用程序。这也意味着数据库结构是相同的。
我需要在生产环境中恢复数据库。我只是不确定为什么 context.Database.Migrate()
会抛出错误?
完整错误:
Application startup exception: System.Data.SqlClient.SqlException
(0x80131904): Database 'MyDatabaseName' already exists. Choose a
different database name. at
System.Data.SqlClient.SqlConnection.OnError(SqlException exception,
Boolean breakConnection, Action1 wrapCloseInAction) at
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException
exception, Boolean breakConnection, Action
1 wrapCloseInAction) at
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject
stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at
System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,
SqlCommand cmdHandler, SqlDataReader dataStream,
BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject
stateObj, Boolean& dataReady) at
System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String
methodName, Boolean async, Int32 timeout, Boolean asyncWrite) at
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, IReadOnlyDictionary
2
parameterValues) at
Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteNonQuery(IRelationalConnection
connection, IReadOnlyDictionary2 parameterValues) at
Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection
connection, IReadOnlyDictionary
2 parameterValues) at
Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1
migrationCommands, IRelationalConnection connection) at
Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.Create()
at
Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String
targetMigration) at
Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.Migrate(DatabaseFacade
databaseFacade) at MyProject.Startup.Configure(IApplicationBuilder
app, AppUserManager userManager, IServiceProvider serviceProvider) in
C:\GitLab-Runner\buildscab42e4[=25=]\web\MyProject\Startup.cs:line 582
--- End of stack trace from previous location where exception was thrown --- at
Microsoft.AspNetCore.Hosting.ConventionBasedStartup.Configure(IApplicationBuilder
app) at
Microsoft.AspNetCore.Server.IISIntegration.IISSetupFilter.<>c__DisplayClass4_0.b__0(IApplicationBuilder
app) at
Microsoft.AspNetCore.Hosting.Internal.AutoRequestServicesStartupFilter.<>c__DisplayClass0_0.b__0(IApplicationBuilder
builder) at
Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
ClientConnectionId:7f6b84a3-e0ea-42c7-947d-a9cafdaffbfa Error
Number:1801,State:3,Class:16 Hosting environment: Production Content
root path: C:\WWW\MyProject Now listening on: http://127.0.0.1:24830
Application started. Press Ctrl+C to shut down. Application is
shutting down...
可能是数据库是由某些 else/earlier 迁移创建的。
您可以通过在 Sql server management studio
中查看数据库是否在列表中(不应该)来验证是否属于这种情况。然后尝试创建同名数据库。如果您再次遇到错误,那是因为它已经被创建了。
至于解决方案,您可以简单地等到数据库存在,这样您就可以再次迁移,但这并不总是可行的。
另一种方法是尝试捕获此异常并添加重试机制。
try
{
// migrate
}
catch (SqlException exception) when (exception.Number == 1801)
{
// retry
}
这是一个令人讨厌的人。数据库确实存在(我确实恢复了它),但问题是数据库的备份所有者也被转移了。
服务器上不存在本地主机所有者的用户。所以迁移没有找到数据库(因为它没有访问权限)所以它试图创建一个新的。
在开始讨论可能的修复之前,我们需要了解一件重要的事情:迁移模式是确保您正在处理的所有数据库(并且您将用于连接您的app with) 将在任何给定环境(测试、阶段、生产、灾难恢复等)中具有一致且最新的结构;如果您选择使用它,您能做的最好的事情就是坚持模式最佳实践并确保在需要时调用 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()
方法仅在数据库尚不存在时才以编程方式执行:这对于测试环境来说是完美的,您每次都可以删除并重新创建数据库无需担心丢失实际数据,and/or 对于您希望手动更新数据库的任何其他上下文——例如使用 dotnet ef
powershell 命令。这对性能有好处,也可以避免 Migrate()
方法中的 SqlException
,因为只要没有数据库开始,它只会 运行,从而防止发现错误或过时的机会迁移数据。
如果您对 Exists()
方法在幕后的实际作用感到好奇,您可以通过查看 SqlServer.Storage/Internal/SqlServerDatabaseCreator.cs class within the EF Core’s official GitHub repository 中的魔法——只是尝试打开连接并捕获 SqlException 和 return false 或 return true。可能不是您希望在那里找到的最好的东西,但总比没有好(至少它可以完成工作)。
如果您需要更多信息,请查看 the blog post that I wrote on such issue。
将 IIS APPPOOL 用户添加到数据库的用户列表中 MyDatabaseName
我是 运行 ASP.NET Core 2.1 和 EF Core 2.1 应用程序,在 Windows Server 2016 和 SQL Server 2017 Web 版上。
在 Startup.cs
中的 public void Configure(IApplicationBuilder app, ...
方法结束时,我调用了 context.Database.Migrate();
。这适用于迁移。
一切正常。
现在我在 SQL Server 2016 的开发环境中备份数据库,将 MyDatabaseName
.bak
文件移动到服务器并在服务器上恢复数据库 MyDatabaseName
并重新启动 IIS 站点.
当我启动应用程序(打开浏览器)时出现以下错误:
Application startup exception: System.Data.SqlClient.SqlException (0x80131904): Database 'MyDatabaseName' already exists. Choose a different database name.
行内:context.Database.Migrate();
。
完整错误在底部。
如果我将 MyDatabaseName
更改为 MyDatabaseNameX
(不存在),则创建数据库,应用所有迁移,我可以重置 IIS,启动应用程序。如果我恢复数据库,我会收到错误 already exists
.
相同的应用程序(完全相同的dll)在开发和生产环境中运行应用程序。这也意味着数据库结构是相同的。
我需要在生产环境中恢复数据库。我只是不确定为什么 context.Database.Migrate()
会抛出错误?
完整错误:
Application startup exception: System.Data.SqlClient.SqlException (0x80131904): Database 'MyDatabaseName' already exists. Choose a different database name. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action
1 wrapCloseInAction) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action
1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite) at 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, IReadOnlyDictionary
2 parameterValues) at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary2 parameterValues) at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary
2 parameterValues) at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands, IRelationalConnection connection) at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.Create() at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration) at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.Migrate(DatabaseFacade databaseFacade) at MyProject.Startup.Configure(IApplicationBuilder app, AppUserManager userManager, IServiceProvider serviceProvider) in C:\GitLab-Runner\buildscab42e4[=25=]\web\MyProject\Startup.cs:line 582 --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.Configure(IApplicationBuilder app) at Microsoft.AspNetCore.Server.IISIntegration.IISSetupFilter.<>c__DisplayClass4_0.b__0(IApplicationBuilder app) at Microsoft.AspNetCore.Hosting.Internal.AutoRequestServicesStartupFilter.<>c__DisplayClass0_0.b__0(IApplicationBuilder builder) at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication() ClientConnectionId:7f6b84a3-e0ea-42c7-947d-a9cafdaffbfa Error Number:1801,State:3,Class:16 Hosting environment: Production Content root path: C:\WWW\MyProject Now listening on: http://127.0.0.1:24830 Application started. Press Ctrl+C to shut down. Application is shutting down...
可能是数据库是由某些 else/earlier 迁移创建的。
您可以通过在 Sql server management studio
中查看数据库是否在列表中(不应该)来验证是否属于这种情况。然后尝试创建同名数据库。如果您再次遇到错误,那是因为它已经被创建了。
至于解决方案,您可以简单地等到数据库存在,这样您就可以再次迁移,但这并不总是可行的。 另一种方法是尝试捕获此异常并添加重试机制。
try
{
// migrate
}
catch (SqlException exception) when (exception.Number == 1801)
{
// retry
}
这是一个令人讨厌的人。数据库确实存在(我确实恢复了它),但问题是数据库的备份所有者也被转移了。
服务器上不存在本地主机所有者的用户。所以迁移没有找到数据库(因为它没有访问权限)所以它试图创建一个新的。
在开始讨论可能的修复之前,我们需要了解一件重要的事情:迁移模式是确保您正在处理的所有数据库(并且您将用于连接您的app with) 将在任何给定环境(测试、阶段、生产、灾难恢复等)中具有一致且最新的结构;如果您选择使用它,您能做的最好的事情就是坚持模式最佳实践并确保在需要时调用 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()
方法仅在数据库尚不存在时才以编程方式执行:这对于测试环境来说是完美的,您每次都可以删除并重新创建数据库无需担心丢失实际数据,and/or 对于您希望手动更新数据库的任何其他上下文——例如使用 dotnet ef
powershell 命令。这对性能有好处,也可以避免 Migrate()
方法中的 SqlException
,因为只要没有数据库开始,它只会 运行,从而防止发现错误或过时的机会迁移数据。
如果您对 Exists()
方法在幕后的实际作用感到好奇,您可以通过查看 SqlServer.Storage/Internal/SqlServerDatabaseCreator.cs class within the EF Core’s official GitHub repository 中的魔法——只是尝试打开连接并捕获 SqlException 和 return false 或 return true。可能不是您希望在那里找到的最好的东西,但总比没有好(至少它可以完成工作)。
如果您需要更多信息,请查看 the blog post that I wrote on such issue。
将 IIS APPPOOL 用户添加到数据库的用户列表中 MyDatabaseName