【问题标题】:Best way to coordinate atomic transactions between different business services in .NET Core / EF Core 2.1?在 .NET Core / EF Core 2.1 中协调不同业务服务之间的原子事务的最佳方式?
【发布时间】:2019-02-07 11:56:01
【问题描述】:

假设您有一个 UsersService、一个 TenantsService 和一个 TenantUserRolesService。

这些服务中的每一个都有一个“create”方法来创建它们的实体,并且注入了相同的 DbContext 依赖项,但注入了 Identity UserManager 类的 UsersService 除外。

您的目标是提供一个 API 端点,允许新租户注册,从而创建用户、租户和 TenantUserRole 实体。 TenantUserRole 是最后创建的,它是一个关联实体,具有新创建的用户、新创建的租户和“所有者”角色的外键。

在这 3 个服务之间创建原子事务的最佳方法是什么,这样如果单个创建失败,所有内容都会回滚,并且数据库不会处于损坏状态,即存在没有用户的租户或没有用户的用户等。

我看过:https://docs.microsoft.com/en-us/ef/core/saving/transactions,但我不知道是否有办法在不同的服务类之间使用这些方法。

我能想到的唯一方法就是采取命令式的方式,手动检查每次创建的结果,如果有错误则使用同一个实体服务删除最近创建的实体。

我希望有一个对该主题更了解的人可以为我指明正确的方向。

谢谢

【问题讨论】:

  • 如果所有服务都使用相同的底层数据库上下文,您只需在其上打开一个事务,运行所有三个服务,然后完成该事务。这是因为数据库上下文是请求范围的,所以所有服务都可以使用同一个实例。
  • @poke 谢谢!数据库上下文是请求范围的,这对我来说并没有点击。

标签: c# .net entity-framework asp.net-core entity-framework-core


【解决方案1】:

假设您正在构建 RESTFul 服务,请记住,根据定义,REST 服务是无状态的,它们不应参与跨越多个服务的事务边界。

您的服务看起来像纳米服务。您的数据高度相关,因此您分解服务的方式感觉非常不自然。如果您的应用程序需要显示所有租户的列表怎么办?您是否考虑过实施 HATEOUS 的性能影响和复杂性?

我的第一个建议是改造您的服务。用户角色、用户和可以说是租户,您定义它的方式应该在单个 API 中。它们都与用户相关,您还指出它们都共享相同的dbContext。如果这不可能,架构师解决您试图解决的问题的方式是通过最终一致性的概念,即通过某种后台同步来同步用户、租户和用户角色存储过程。

请不要试图将您对 3 个 API 的调用封装在一个事务中。这不仅完全反 REST,而且如果它们都共享同一个数据库,那么您很可能不需要 3 个 API。

【讨论】:

    【解决方案2】:

    如果您的事务跨越所谓的Transactional integration antipattern 的服务边界。

    解决该问题的一种方法是使用外部编排服务(例如Camunda)。它的职责是处理业务流程并在失败时采取一些补偿措施。 它不会完全是“事务性的”——ACID 属性将通过补偿来实现。

    您可以自己创建该服务。它的责任是管理特定的工作流程。

    【讨论】:

      猜你喜欢
      • 2020-05-02
      • 2020-07-07
      • 2018-12-23
      • 1970-01-01
      • 2019-07-15
      • 2019-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多