Search code examples
typescriptnestjstypeorm

Is it safe to use global instance of the entity repository for saving multiple objects in a transaction (TypeORM)?


From TypeORM docs about transactions:

The most important restriction when working in an transaction is, to ALWAYS use the provided instance of entity manager - transactionalEntityManager in this example. If you'll use global manager (from getManager or manager from connection) you'll have problems. You also cannot use classes which use global manager or connection to execute their queries. All operations MUST be executed using the provided transactional entity manager.

then is it safe to use a repository like this:

    await this.myRepository.save(entities);

assuming that I want all my entities to be saved within a single transaction?

I use NestJS and my repository is coming from a global module injection scope:

@Injectable()
export class MyService {
  constructor(
    @InjectRepository(MyEntity) private readonly myRepository: Repository<MyEntity>,
  ) {}
  ...
}

meaning it's the same repository instance every time. From SQL debug logs I see that a transaction is started correctly and all the insert operations for given entities are within a single transaction, but the question is whether there is a corner case where this will not work?

What does:

If you'll use global manager (from getManager or manager from connection) you'll have problems.

refer to exactly?


Solution

  • Ok, so how the transaction works here

    await getManager().transaction(async transactionalEntityManager => {
        
    });
    

    You have a dedicated instance of EntityManager which will collect queries which will be run in the same transaction. The warning you are asking about says that you can't do things like that

    await getManager().transaction(async transactionalEntityManager => {
        await transactionalEntityManager.save(users);
        await getRepository(Photo).save(photos); 
    });
    

    Because the part that is not run on the transactionalEntityManager will not be registered as a scope of the same transaction as the first one.

    In your case everything is fine because save() creates its own transaction for the signal save operation. You need to handle it by yourself when you need to do multiple saves in a single transaction. In such case you must use the same instance of query runner as described here https://docs.nestjs.com/techniques/database#transactions