我运行了一个长时间运行的DbContext.SaveChanges()并尝试在排队的background task.中执行它,但是当代码访问Backgroundtask并且控制器内的请求被返回时,DbContext被处置并重新初始化。
总体我的问题(已更新,因为它似乎不是100%清楚-我的错!):
更明确一点:当我向dbContext添加更改并添加/启动后台任务以保存此更改时,通过返回请求来处理dbContext。现在,后台任务尝试运行时,无需再保存任何更改,因为dbContext不再相同。
当我将Servicelifetime从Scoped更改为Singleton(DbContext和UnitOfWork)时,一切正常。但这不是解决方案:-/
第二个问题:如果我必须在后台任务中添加更改-向该任务传递参数的最佳方法是什么?
我已经在Startup.cs中注册了BackGroundTaskService和DbContext / UnitOfWork,并通过在Controller中进行依赖注入来捕获它。
启动代码部分:
services.AddDbContext<MyDbContext>
(options =>
{
options.UseSqlServer(connectionString);
},
ServiceLifetime.Scoped
);
services.AddScoped<IMyUnitOfWork, MyUnitOfWork>();
// Background Services
services.AddHostedService<QueuedHostedService>();
services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();
BackgroundTask代码部分:
public class QueuedHostedService : BackgroundService
{
private readonly ILogger _logger;
private readonly IServiceScopeFactory _scopeFactory;
public QueuedHostedService(IBackgroundTaskQueue taskQueue,ILoggerFactory loggerFactory, IServiceScopeFactory scopeFactory)
{
TaskQueue = taskQueue;
_logger = loggerFactory.CreateLogger<QueuedHostedService>();
_scopeFactory = scopeFactory;
}
public IBackgroundTaskQueue TaskQueue { get; }
protected async override Task ExecuteAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Queued Hosted Service is starting.");
while (!cancellationToken.IsCancellationRequested)
{
var workItem = await TaskQueue.DequeueAsync(cancellationToken);
try
{
using (var scope = _scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>();
await dbContext.SaveChangesAsync();
// the call workItem is not working -> object disposed
//await workItem(cancellationToken);
}
}
catch (Exception ex)
{
_logger.LogError(ex,
$"Error occurred executing {nameof(workItem)}.");
}
}
_logger.LogInformation("Queued Hosted Service is stopping.");
}
}
控制器代码部分:
_unitOfWork.Repository.AddRange(MyObjectList);
_queue.QueueBackgroundWorkItem(async token =>
{
await _unitOfWork.CompleteAsync();
});
UnitOfWork代码部分:
public Task<int> CompleteAsync()
{
return _context.SaveChangesAsync();
}
谢谢!
更新:
我之所以在后台任务中保存dbcontext更改的方法,是因为dbcontext必须插入80k行,并且ORM生成更多的insert-commands。所以我必须找到一种解决方案以使插入更加有效,而不是将问题隐藏在后台任务中。 流行语:ETL,SSIS