4

I have some question with TypeORM transaction. So my code is like below:

  public createOrderTransaction = async (
    data: CreateOrderInputDTO,
  ): Promise<Order> => {
    const queryRunner = this.connection.createQueryRunner();
    await queryRunner.startTransaction();
    try {
      const order = await this.createOrder(data);
      await this.createOrderRecord(order.id, data);
      await queryRunner.commitTransaction();
      return order;
    } catch (error) {
      this.logger.error(
        "Transaction Error: 'createOrderTransaction' is failed: ",
        error,
      );
      if (queryRunner.isTransactionActive) {
        await queryRunner.rollbackTransaction();
      }
    }
  };

And one function like createOrder use query builder:

private createOrder = async (data: CreateOrderInputDTO): Promise<Order> => {
    const { identifiers } = await this.orderRepository
      .createQueryBuilder('order')
      .insert()
      .into(Order)
      .values([data])
      .execute();

    await this.saveOrderDetail(identifiers[0].id, data.orderDetails);

    await this.orderRepository
      .createQueryBuilder('order')
      .relation(Order, 'orderDetails')
      .of(identifiers[0].id)
      .add(data.orderDetails);

    return this.getOrder(identifiers[0].id);
  };

But when I try it, and if it fire some error middle of logic, rollback doesn't work. The way I see it, It seem that query builder doesn't support transaction. So Is there any way to use quert builder with transaction?

2 Answers 2

3

Self Answer... After I am looking into TypeORM index.d.ts, I take it that there are some parameter in createQueryBuilder named queryRunner so. If you input there your own query runner for transaction you can use queryBuilder with queryRunner

As like:

  public createOrderTransaction = async (
    data: CreateOrderInputDTO,
  ): Promise<Order> => {
    const queryRunner = this.connection.createQueryRunner();

    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      const order = await this.createOrder(data, queryRunner);
      await this.createOrderRecord(order.id, data, queryRunner);
      await queryRunner.commitTransaction();
      return order;
    } catch (error) {
      this.logger.error(
        "Transaction Error: 'createOrderTransaction' is failed: ",
        error,
      );
      if (queryRunner.isTransactionActive) {
        await queryRunner.rollbackTransaction();
      }
    }
  };

createOrder as like:

 private createOrderRecord = async (
    orderId: string,
    data: CreateOrderInputDTO,
    queryRunner?: QueryRunner,
  ): Promise<void> => {
    await this.orderRecordRepository
      .createQueryBuilder('order_record', queryRunner)
      .insert()
      .into(OrderRecord)
      .values([
        {
          ...data,
          orderId,
          createdAt: new Date(),
        },
      ])
      .execute();

    await this.orderRecordRepository
      .createQueryBuilder('order_record', queryRunner)
      .relation(OrderRecord, 'orderDetails')
      .of(orderId)
      .add(data.orderDetails);
  };
Sign up to request clarification or add additional context in comments.

Comments

0

I don't know if this helps help anyone facing this question, but instead of doing in above answer, we can use dataSource, as suggested in this official TypeOrm transaction document, and instead of adding Entity in queryBuilder, add it to .from()

await myDataSource.manager.transaction(async (transactionalEntityManager) => {
// We can use 'transactionalEntityManager' to create queryBuilder here:
await transactionalEntityManager.createQueryBuilder()
  .from(Order, 'order')
  .insert()
  .into(OrderRecord)
  .values([
    {
      ...data,
      orderId,
      createdAt: new Date(),
    },
  ])
  .execute();

// And of course similar with relation table:
await transactionalEntityManager
  .createQueryBuilder()
  .from(Order, 'order')
  .relation(OrderRecord, 'orderDetails')
  .of(orderId)
  .add(data.orderDetails);
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.