我在Windows Server2016和SQL Server2017网络版上运行ASP.NET核心2.1和EF核心2.1应用程序。
在Startup.cs
中public void Configure(IApplicationBuilder app, ...
方法的末尾,我调用了context.Database.Migrate();
。这适用于迁移。
一切正常。
现在我用SQL Server2016在我的开发环境中备份数据库,将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 exception,Boolean breakConnection,
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,Boolean async,timeout,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)处的布尔asyncWrite),Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands处的IReadOnlyDictionary2 parameterValues) at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary
2 parameterValues),在Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.Create()处的Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String连接)在Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.Migrate(DatabaseFacade databaseFacade处)在MyProject.Startup.Configure(IApplicationBuilder app,AppUserManager userManager,在C:\GitLab-Runner\builds\7cab42e4\0\web\MyProject\Startup.cs:line 582中的IServiceProvider serviceProvider) -来自之前抛出异常的位置的堆栈跟踪的结束-在Microsoft.AspNetCore.Hosting.Internal.AutoRequestServicesStartupFilter.<>c__DisplayClass0_0.b__0(的Microsoft.AspNetCore.Hosting.ConventionBasedStartup.Configure(IApplicationBuilder应用)在Microsoft.AspNetCore.Server.IISIntegration.IISSetupFilter.<>c__DisplayClass4_0.b__0(IApplicationBuilder应用在Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication() ClientConnectionId:7f6b84a3-e0ea-42c7-947d-a9cafdaffbfa错误号:1801,IApplicationBuilder builder),状态:3,类:16托管环境:生产内容根路径: C:\WWW\MyProject正在侦听:http://127.0.0.1:24830应用程序已启动。按Ctrl+C键关闭。应用程序正在关闭...
发布于 2018-07-17 23:14:55
这是一个令人讨厌的问题。数据库确实存在(我确实恢复了它),但问题是数据库的备份所有者也被转移了。
服务器上不存在本地主机上的所有者用户。所以迁移没有找到数据库(因为它没有访问权限),所以它会尝试创建一个新的数据库。
发布于 2018-09-30 06:30:34
在开始讨论可能的修复之前,我们需要了解一件重要的事情:迁移模式是一种很好的方法,可以确保您正在处理的所有数据库(以及您将用来连接应用程序的数据库)在任何给定的环境中都具有一致和最新的结构-测试、阶段、生产、灾难恢复等等;如果您选择使用它,您可以做的最好的事情就是坚持使用该模式的最佳实践,并确保在需要的时候调用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。
发布于 2018-07-17 18:44:39
一种可能性是数据库是由其他或更早的迁移创建的。
如果数据库在列表中(不应该在列表中),您可以通过在Sql server management studio
中查看来验证是否属于这种情况。然后尝试创建具有相同名称的数据库。如果你再次得到这个错误,那是因为它已经被创建了。
至于解决方案,您可以简单地等待数据库存在,这样您就可以再次迁移,但这并不总是实用的。另一种方法是尝试捕获此异常并添加重试机制。
try
{
// migrate
}
catch (SqlException exception) when (exception.Number == 1801)
{
// retry
}
https://stackoverflow.com/questions/50981005
复制相似问题