Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

290
Visualizações
What is the correct way to work with transactions with NestJs and TypeORM?

I am using NestJS with TypeORM. I have several modules and each module contain service. There are some modules that import other modules and use their services.

// In Person Module
@Injectable()
class UserService {
  constructor(
    @InjectRepository(User)
    private usersRepository: Repository<User>
  ) {}

  public async deleteUsersByCompany(companyId: string) {
    const usersToDelete = await this.usersRepository
      .createQueryBuilder('user')
      .where('user.companyId = :companyId', { companyId })
      .getMany();

    if (usersToDelete.length > 0) {
      await this.usersRepository.delete(
        usersToDelete.map((user) => user.id),
      );
    }
  }

  ...
}

// Company Module

@Injectable()
class CompanyService {
  constructor(
    @InjectRepository(Company)
    private companysRepository: Repository<Company>,
    private usersService: UserService
  ) {}

  public async deleteCompany(companyId: string) {
    const companyToDelete = await this.companysRepository.find(companyId);

    if (companyToDelete) {
      await usersService.deleteUsersByCompany(companyToDelete.id)
      await this.companysRepository.delete(companyToDelete);
    }
  }

  ...
}

In this example:

  1. I want usersService.deleteUsersByCompany to be atomic operation
  2. I want companyService.deleteCompany to be atomic operation
  3. Both usersService.deleteUsersByCompany and companyService.deleteCompany can be triggered by the user

I want to wrap both actions in transaction. I've read NestJS documentation and TypeOrm documentation but couldn't find an answer how to do this properly.
The main thing here is that usersService.deleteUsersByCompany is being called by companyService.deleteCompany.

  1. How can I support such "nested transactions"?
  2. Does QueryRunner replace the Repository pattern?
  3. Should my services hold both Repository and Connection instances? Repository for non-transactional operations and connection to get QueryRunner?
over 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

The easiest way to use transaction is using the EntityManager API, check a simple example from a microservice:

import { WRITE_CONNECTION } from '@my-api/common';
import { Injectable, Logger } from '@nestjs/common';
import { RpcException } from '@nestjs/microservices';
import { InjectEntityManager } from '@nestjs/typeorm';
import { EntityManager } from 'typeorm';

@Injectable()
export class MyService {
  private logger = new Logger(MyService.name);
  constructor(
    @InjectEntityManager(WRITE_CONNECTION) private entityManager: EntityManager,
  ) {}

  async saveSomething(data: string): Promise<void> {
    try {
      return await this.entityManager.transaction(async (entityManager) => {
        const firstRepository = entityManager.getCustomRepository(FirstRepository);
        const secondRepository = entityManager.getCustomRepository(SecondRepository);

        const firstRecord = firstRepository.create({ data });
        await firstRepository.save(firstRecord);

        const secondRecord = secondRepository.create({ data });
        await secondRepository.save(secondRecord);

        // Save entities directly
        await entityManager.save([...]);
      });
    } catch (error) {
      this.logger.error(`Failed saving something, error ${error.message}`, error.stack);
      throw new RpcException(error.message);
    }
  }
}

As you can see, we use the entityManager for read and write operations in the same transaction that can execute a rollback automatically if any of these operations fails.

For more details check the repository of TypeORM with examples here.

So if you want to wrap both actions in the same transaction, you need to call a method and pass the repository as a parameter. e.g:

async findOneItem(
  itemId: number,
  myRepository: MyRepository = this.myRepository, // Optional parameter if needed
) {
  return await myRepository.findOne(itemId);
}
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda