skip to Main Content

I have a setup for my NestJS application in which I am using typeorm with a PostgreSQL database. In the setup, I am using repository mode to query the database. Now I want to use database transactions with my queries, but I am not able to use transactions because I am using one transaction with multiple queries from different repositories, and a transaction uses an entity manager, which has to be used to query the database in order to access the same transaction for all the queries in the scope.

Entity One

@Injectable()
export class EntityOneService extends BaseService<EntityOne> {
  repository: Repository<EntityOne>;
  constructor(private connection: Connection) {
    super();
    this.repository = this.connection.getRepository(EntityOne);
  }
}

Entity Two

import { Injectable } from '@nestjs/common';
import { Connection, Repository } from 'typeorm';

import { EntityTwo } from '../entities/lesson.entity';
import { BaseService } from './baseService/base-service.service';

@Injectable()
export class EntityTwoService extends BaseService<EntityTwo> {
  repository: Repository<EntityTwo>;
  constructor(private connection: Connection) {
    super();
    this.repository = this.connection.getRepository(EntityTwo);
  }
}

This is how to initialize the repository from a database table. Now I want to query the database using transaction in repository mode.

const entityOne = await this.entityOneService.find()
const entityTwo = await this.entityTwoService.find()

I want to query both with the same transaction. I have user sequelize before typeorm, and in sequelize there is a method named transaction which can used as follows.

this.sequelize.transaction(async transaction => {
    const entityOne = await this.entityOneService.findAll({transaction})
    const entityTwo = await this.entityTwoService.findAll({transaction})
})

I want to do something like that in typeorm, if possible how can I implement it?

2

Answers


  1. Transactions

    • Creating and using transactions
    • Using QueryRunner to create and control state of single database connection

    Creating and using transactions

    Transactions are created using DataSource or EntityManager.
    Examples:

    await myDataSource.transaction(async (transactionalEntityManager) => {
      // execute queries using transactionalEntityManager
    });
    

    or

    await myDataSource.manager.transaction(async (transactionalEntityManager) => {
      // execute queries using transactionalEntityManager
    });
    

    Everything you want to run in a transaction must be executed in a callback:

    await myDataSource.manager.transaction(async (transactionalEntityManager) => {
      await transactionalEntityManager.save(users);
      await transactionalEntityManager.save(photos);
      // ...
    });
    

    Using QueryRunner to create and control state of single database connection

    QueryRunner provides a single database connection.
    Transactions are organized using query runners.
    Single transactions can only be established on a single query runner.
    You can manually create a query runner instance and use it to manually control transaction state.
    Example:

    // create a new query runner
    const queryRunner = dataSource.createQueryRunner();
    
    // establish real database connection using our new query runner
    await queryRunner.connect();
    
    // now we can execute any queries on a query runner, for example:
    await queryRunner.query("SELECT * FROM users");
    
    // we can also access entity manager that works with connection created by a query runner:
    const users = await queryRunner.manager.find(User);
    
    // lets now open a new transaction:
    await queryRunner.startTransaction();
    
    try {
      // execute some operations on this transaction:
      await queryRunner.manager.save(user1);
      await queryRunner.manager.save(user2);
      await queryRunner.manager.save(photos);
    
      // commit transaction now:
      await queryRunner.commitTransaction();
    } catch (err) {
      // since we have errors let's rollback changes we made
      await queryRunner.rollbackTransaction();
    } finally {
      // you need to release query runner which is manually created:
      await queryRunner.release();
    }
    

    There are 3 methods to control transactions in QueryRunner:

    • startTransaction – starts a new transaction inside the query runner instance.
    • commitTransaction – commits all changes made using the query runner instance.
    • rollbackTransaction – rolls all changes made using the query runner instance back.

    Source: https://typeorm.io/transactions

    Login or Signup to reply.
  2. https://stackoverflow.com/a/70140732 I think this is an example for a solution with multiple repositories.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search