Выпуск
Для тестирования я создаю новую работу, она просто использует IRepository для чтения данных из базы данных. Код как ниже:
public class TestJob : BackgroundJob<string>, ITransientDependency
{
private readonly IRepository<Product, long> _productRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager;
public TestJob(IRepository<Product, long> productRepository,
IUnitOfWorkManager unitOfWorkManager)
{
_productRepository = productRepository;
_unitOfWorkManager = unitOfWorkManager;
}
public override void Execute(string args)
{
var task = _productRepository.GetAll().ToListAsync();
var items = task.Result;
Debug.WriteLine("test db connection");
}
}
Затем я создаю новую службу приложений для запуска задания. Фрагмент кода, как показано ниже:
public async Task UowInJobTest()
{
await _backgroundJobManager.EnqueueAsync<TestJob, string>("aaaa");
}
Когда я проверяю задание, при выполнении var task = _productRepository.GetAll (). ToListAsync ();
выдает следующее исключение
Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.Object name: 'AbpExampleDbContext'.
Решение
S1 : добавить атрибут UnitOfWork в метод выполнения. Это может решить проблему. Но это не лучше для моего реального сценария. В моем реальном сценарии задание является долгосрочным и имеет много операций с БД. Если включить метод UnitOfWork for Execute, он будет блокировать ресурс БД на длительное время. Так что это не решение для моего сценария.
[UnitOfWork]
public override void Execute(string args)
{
var task = _productRepository.GetAll().ToListAsync();
var items = task.Result;
Debug.WriteLine("test db connection");
}
S2: Явное выполнение операции с БД в UnitOfWork. Кроме того, это может решить проблему, но я не думаю, что это лучшая практика. В моем примере, просто прочитайте данные из базы данных, транзакция не требуется. Несмотря на то, что проблема решена, но я не думаю, что это правильный путь.
public override void Execute(string args)
{
using (var unitOfWork = _unitOfWorkManager.Begin())
{
var task = _productRepository.GetAll().ToListAsync();
var items = task.Result;
unitOfWork.Complete();
}
Debug.WriteLine("test db connection");
}
Вопрос
Мой вопрос: как правильно и наилучшим образом выполнить операцию с БД в BackgroundJob?
Есть еще один вопрос, Я создаю новый сервис приложений и отключаю UnitOfWrok, но он работает нормально. Пожалуйста, смотрите код, как показано ниже. Почему он отлично работает в службе приложений, но не работает в BackgroundJob?
[UnitOfWork(IsDisabled =true)]
public async Task<GetAllProductsOutput> GetAllProducts()
{
var result = await _productRepository.GetAllListAsync();
var itemDtos = ObjectMapper.Map<List<ProductDto>>(result);
return new GetAllProductsOutput()
{
Items = itemDtos
};
}