如何在多个服务方法之间共享 'unit of work'?

How can I share a 'unit of work' between multiple service methods?

我在作为原型的一部分构建的应用程序服务中实现工作单元模式时遇到问题。我想我是:

a) Missing something in the capabilities of autofac that I don't know it can do OR

b) Misusing the unit of work pattern entirely and need to refactor my service and/or repositories.

基本上我的问题源于我服务中的代码共享。具体来说,我有一个名为 CreateCustomerAsync(…) 的服务方法,在该方法中我构建了一个工作单元(包装一个数据库连接并开始一个数据库事务)并使用一个存储库插入到几个数据库 table 中。在我想从该方法(并且在 UOW 的范围内)调用另一个名为 AddCustomerToGroupAsync(…) 的服务方法以便(在同一 UOW 内)将客户添加到组中(添加一行link table)。 AddCustomerToGroupAsync 本身在内部使用自己的工作单元,以确保其存储库操作也在数据库事务中发生。

目前我无法在同一个 UOW 中完成所有这些操作 - 事实上,使用这样的代码实际上根本不起作用,因为最里面的 UOW 是 运行 通过不同的连接它还看不到外部交易插入的客户!我可以重新排序代码,以便 AddCustomerToGroupAsync 调用在父 UOW 之外,但随后我失去了数据库完整性。

所以 - 我大致(这在语法上不正确 - 但代表了我面临的问题)是这样的:

public async Task<int> CreateCustomerAsync(string name, int groupid)
{
    // do some validation etc..

    // NOTE: UnitOfWork and CustomerRepository are scoped to InstancePerMatchingLifetimeScope for 'tx'
    using(var scope = this.Container.BeginLifetimeScope("tx"))
    using(var uow = scope.Resolve<UnitOfWork>())
    {
        // NOTE: ResolveRepository is an extension method - the repo is having the uow injected into it
        var customerrepository = uow.ResolveRepository<CustomerRepository>();

        // multiple repository calls all within the same UOW/db transaction
        int newid = await customerrepository.CreateAsync(name);
        await customerrepository.ActivateAsync(newid);

        // here we invoke our seperate service method... and which I would *like* to execute within
        // this same UOW - so if it fails then all of the db statements executed so far get rolled back
        await this.AddCustomerToGroupAsync(newid, groupid);

        uow.Commit();
    }
}

public async Task<bool> AddCustomerToGroupAsync(int customerId, int groupId)
{
    // really here I'd LIKE to resolve the same lifetime scope that was constructed in the parent if it doesnt
    // exist with the tag specified already...
    // if i could do that then I would be able to resolve the *same* unit of work which would be a step forward
    using(var scope = this.Container.BeginLifetimeScope("tx"))
    using (var uow = scope.Resolve<UnitOfWork>())
    {
        var grouprepository = uow.ResolveRepository<GroupRepository>();

        // two repository calls that need to be wrapped in the same UOW/TX
        int linkid = await grouprepository.CreateLinkAsync(customerId, groupId);
        await grouprepository.ActivateAsync(linkid);

        uow.Commit();
    }
}

任何尝试实现此目标的指示,或者我的方法从根本上被误导了?

干杯。

考虑为 AddCustomerToGroupAsync 编写一个私有方法来完成大部分工作。

   private async Task<bool> AddCustomerToGroupInternalAsync(int customerId, int groupId, UnitOfWork uow)
   { ../* All the code in the AddCustomerToGroupAsync inside the unitOfWork */. }

对于现有的 AddCustomerToGroupAsync 方法,您可以打开一个范围,解析一个 unitOfWork 并将其传递给 AddCustomerToGroupInternalAsync 方法。同样,对于现有的 CreateCustomerAsync 方法,您可以将在该方法中解析的 UnitOfWork 传递给 AddCustomerToGroupInternalAsync 方法。

在这两种情况下,您都可以在调用 AddCustomerToGroupInternalAsync 之后调用 uow.Commit。