EF Core运行时创建数据库后迁移失败,dotnet ef命令却正常
问题
应用首次启动时调用context.Database.Migrate(),仅能创建数据库,但迁移执行前抛出错误;多次尝试有时出现超时异常,有时迁移耗时超10分钟。但使用dotnet ef database update命令执行迁移完全正常。
复现环境
- SQL Server版本:Microsoft SQL Server 2022 - 16.0.4105.2 Express Edition (64-bit) on Linux (Ubuntu 22.04.3 LTS)
- EF Core相关包版本:
Microsoft.EntityFrameworkCore 8.0.2 Microsoft.EntityFrameworkCore.Design 8.0.2 Microsoft.EntityFrameworkCore.SqlServer 8.0.2 - dotnet-ef工具版本:8.0.2
- 启动代码:
using var context = scope.ServiceProvider.GetRequiredService<MyContext>(); context.Database.Migrate(); - 连接字符串所用SQL用户拥有sysadmin权限。
解决方案
以下是几种排查和解决的方向:
1. 调整命令超时时间
应用启动时的迁移命令超时可能过短,而dotnet ef工具默认的超时设置更长。可以在DbContext配置中显式设置迁移命令的超时时间:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( "<你的连接字符串>", sqlOptions => sqlOptions.CommandTimeout(120)); // 设置为120秒,可根据需求调整 }
同时,也可以在连接字符串中增加连接超时设置:
Server=<服务器地址>;Database=<数据库名>;User Id=<用户名>;Password=<密码>;Connect Timeout=60;
2. 添加数据库创建后的重试逻辑
SQL Server创建数据库后需要短暂的初始化时间,应用立即执行迁移可能引发连接问题。可以添加重试机制,在迁移失败时等待并重试:
using var scope = host.Services.CreateScope(); var context = scope.ServiceProvider.GetRequiredService<MyContext>(); int retryCount = 3; int delaySeconds = 5; bool migrationSuccess = false; while (retryCount > 0 && !migrationSuccess) { try { context.Database.Migrate(); migrationSuccess = true; } catch (SqlException) { retryCount--; if (retryCount > 0) { Thread.Sleep(TimeSpan.FromSeconds(delaySeconds)); delaySeconds *= 2; // 指数退避 } } }
如果需要更健壮的重试,可引入Polly库实现策略。
3. 确认DbContext的生命周期与服务范围
确保在正确的服务范围内获取DbContext,且Host已完成构建。正确的启动顺序示例:
var host = Host.CreateDefaultBuilder(args) .ConfigureServices((context, services) => { services.AddDbContext<MyContext>(options => options.UseSqlServer(context.Configuration.GetConnectionString("DefaultConnection"))); }) .Build(); // 需在Host构建完成后创建服务范围 using var scope = host.Services.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService<MyContext>(); dbContext.Database.Migrate(); host.Run();
4. 验证迁移脚本一致性
确认应用使用的迁移脚本与dotnet ef工具使用的一致。可尝试清理旧迁移并重新生成:
dotnet ef migrations remove dotnet ef migrations add InitialCreate dotnet ef database update
之后再测试应用启动时的迁移逻辑。
5. 排查SQL Server的阻塞与日志
检查SQL Server是否存在阻塞迁移的进程,可通过以下SQL查询:
-- 查询当前锁信息 SELECT resource_type, resource_database_id, request_mode, request_session_id FROM sys.dm_tran_locks WHERE resource_database_id = DB_ID('<你的数据库名>'); -- 查询当前执行请求 SELECT session_id, command, status, wait_type FROM sys.dm_exec_requests WHERE database_id = DB_ID('<你的数据库名>');
同时查看SQL Server的错误日志,排查是否存在数据库初始化相关的异常。
内容的提问来源于stack exchange,提问作者NTE
相关产品推荐
相关产品推荐

