How to open database connection in a BackgroundJob in ABP application

旧城冷巷雨未停 提交于 2019-12-02 10:02:18

The documentation on Background Jobs And Workers uses [UnitOfWork] attribute.

S1: Add UnitOfWork attribute on execute method. It can address the issue. But it is not better for my actual scenario. In my actual scenario, the job is a long time task, and has much DB operatons, if enable UnitOfWork for Execute method, it will lock db resource for a long time. So this is not a solution for my scenario.

Background jobs are run synchronously on a background thread, so this concern is unfounded.

S2: Execute DB operation in UnitOfWork explicitly. Also, this can address the issue, but I don’t think this is a best practice. In my example,just read data from database, no transaction is required. Even-though the issue is addressed, but I don’t think it’s a correct way.

You can use a Non-Transactional Unit Of Work:

[UnitOfWork(isTransactional: false)]
public override void Execute(string args)
{
    var task = _productRepository.GetAll().ToListAsync();
    var items = task.Result;
}

You can use IUnitOfWorkManager:

public override void Execute(string args)
{
    using (var unitOfWork = _unitOfWorkManager.Begin(TransactionScopeOption.Suppress))
    {
        var task = _productRepository.GetAll().ToListAsync();
        var items = task.Result;
        unitOfWork.Complete();
    }
}

You can also use AsyncHelper:

[UnitOfWork(isTransactional: false)]
public override void Execute(string args)
{
    var items = AsyncHelper.RunSync(() => _productRepository.GetAll().ToListAsync());
}

Conventional Unit Of Work Methods

I create a new application service, and disable UnitOfWork, but it works fine.
Why it works fine in application service, but doesn’t work in 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
    };
}

You are using different methods: GetAllListAsync() vs GetAll().ToListAsync()

Repository methods are Conventional Unit Of Work Methods, but ToListAsync() isn't one.

From the documentation on About IQueryable<T>:

When you call GetAll() outside of a repository method, there must be an open database connection. This is because of the deferred execution of IQueryable<T>. It does not perform a database query unless you call the ToList() method or use the IQueryable<T> in a foreach loop (or somehow access the queried items). So when you call the ToList() method, the database connection must be alive.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!