我正在带有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(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) Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteNonQuery(IRelationalConnection 连接,位于IReadOnlyDictionary2 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关闭。申请是 关闭...
答案 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.cs中EF 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
的用户列表中