Estoy usando NestJS con TypeORM. Tengo varios módulos y cada módulo contiene servicio. Hay algunos módulos que importan otros módulos y utilizan sus servicios.
// 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); } } ... }En este ejemplo:
usersService.deleteUsersByCompany sea una operación atómicacompanyService.deleteCompany sea una operación atómicausersService.deleteUsersByCompany como companyService.deleteCompany pueden ser activados por el usuario Quiero envolver ambas acciones en transacción. He leído la documentación de NestJS y la documentación de TypeOrm, pero no pude encontrar una respuesta sobre cómo hacerlo correctamente.
Lo principal aquí es que usersService.deleteUsersByCompany llama a companyService.deleteCompany .
La forma más fácil de usar la transacción es usar la API de EntityManager, vea un ejemplo simple de un microservicio:
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); } } }Como puede ver, usamos el EntityManager para operaciones de lectura y escritura en la misma transacción que puede ejecutar una reversión automáticamente si alguna de estas operaciones falla.
Para más detalles consulta el repositorio de TypeORM con ejemplos aquí .
Entonces, si desea envolver ambas acciones en la misma transacción, debe llamar a un método y pasar el repositorio como parámetro. p.ej:
async findOneItem( itemId: number, myRepository: MyRepository = this.myRepository, // Optional parameter if needed ) { return await myRepository.findOne(itemId); }