2

我正在为未来的项目评估 Mikro-Orm。有几个问题我要么在文档中找不到答案,要么没有完全理解它们。

让我描述一个最小复杂示例(NestJS):我有一个包含两个实体的订单处理系统:Orders以及Invoices一个用于顺序发票编号的计数器表(法律要求)。值得一提的是,OrderService 创建方法并不总是由控制器调用,也可以通过 crobjob/queue 系统调用。我的问题是关于创建新订单的用例:

class OrderService {
    async createNewOrder(orderDto) {
        const order = new Order();
        order.customer = orderDto.customer;
        order.items = orderDto.items;

        const invoice = await this.InvoiceService.createInvoice(orderDto.items);
        order.invoice = invoice;

        await order.persistAndFlush();

        return order
    }
}

class InvoiceService {
    async create(items): Invoice {
        const invoice = new Invoice();

        invoice.number = await this.InvoiceNumberService.getNextInSequence();

        // the next two lines are external apis, if they throw, the whole transaction should roll back
        const pdf = await this.PdfCreator.createPdf(invoice);
        const upload = await s3Api.uplpad(pdf);

        return invoice;
    }
}

class InvoiceNumberService {
  async getNextInSequence(): number {
      return await db.collection("counter").findOneAndUpdate({ type: "INVOICE" }, { $inc: { value: 1 } });
  }
}

使用所有后续服务调用创建新订单的整个用例应该发生在一个 Mikro-Orm 事务中。因此,如果在 OrderService.createNewOrder() 或随后调用的方法之一中抛出任何东西,则应该回滚整个事务。

  1. Mikro-Orm 不允许 InvoiceNumberService 中显示的原子更新增量。我可以回退到本地 mongo 驱动程序。但是如何确保对 collection.findOneAndUpdate() 的调用与 Mikro-Orm 管理的实体共享相同的事务?

  2. Mikro-Orm 需要一个独特的请求上下文。在 NestJS 的示例中,这个独特的上下文是在控制器级别创建的。在上面的示例中,服务方法不一定由控制器调用。因此,对于 OrderService.createNewOrder() 的每次调用,我都需要一个新的上下文,其生命周期范围为函数调用,对吗?我怎样才能做到这一点?

  3. 如何在服务之间共享相同的请求上下文?在上面的示例中,InvoiceService 和 InvoiceNumberService 需要与 OrderService 相同的上下文才能使 Mikro-Orm 正常工作。

4

1 回答 1

0

我将从坏消息开始,MikroORM 尚不支持 mongodb 事务(尽管它们可能会在几周内登陆,但已经实现了 PoC)。您可以在此处订阅更新:https ://github.com/mikro-orm/mikro-orm/issues/34

但让我回答其余的,因为它将适用:

您可以使用const collection = (em as EntityManager<MongoDriver>).getConnection().getCollection('counter');从内部 mongo 连接实例获取集合。您还可以使用orm.em.getTransactionContext()获取当前的事务上下文(当前仅在 sql 驱动程序中实现,但将来这可能会返回sessionmongo 中的对象)。

另请注意,在 mongo 驱动程序中,默认情况下不会启用隐式事务(尽管它是可配置的),因此您需要通过em.transactional(...).

RequestContext助手自动工作。您只需将其注册为中间件(在 nestjs orm 适配器中自动完成),然后您的请求处理程序(路由/端点/控制器方法)在共享上下文的域中运行。多亏了这一点,DI 中的所有服务都可以共享存储库的单例实例,但它们会自动从域中选择正确的上下文。

你基本上有这个自动请求上下文,然后你可以通过手动创建新的(嵌套的)上下文em.transactional(...)

https://mikro-orm.io/docs/transactions/#approach-2-explicitly

于 2020-02-25T11:05:55.973 回答