3
votes

My Question is around transaction management using nestjs and Typeorm, my db is postgres.

  1. Should I use decorators like @Transaction and @TransactionManager while doing transaction management. I heard that they are going to be removed in new releases. https://github.com/typeorm/typeorm/issues/3251

  2. As a best practise how do we handle a transaction that is inserting or updating multiple tables. I see the following question nestjs / TypeOrm database transaction Is this the right away, can somebody give me a full example. Should I inject connection to my service class and get EntityManager from it and pass it around?

  3. What would be the right way for unit testing such an insert on two tables.

I am right now using Transaction decorators from TypeOrm. All my create code is in a single class, I want to be able to move the code for creation of every entity to be moved to the entity's own service class and expect the transaction rollback still works.

@Transaction({ isolation: "SERIALIZABLE" })
    async createProfile(createProfileDTO: CreateProfileDTO, @TransactionManager() manager?: EntityManager){
...
const profileRepository = manager.getRepository(Profile);
let savedProfile = await profileRepository.save<Profile>(profile);

identifier.profile = savedProfile;
 const identifierRepository = manager.getRepository(Identifier);
 let savedIdentifier = identifierRepository.save(identifier);

}

Alternatively, if I use

 await this.connection.transaction(async transactionalEntityManager => {
            profile = await this.createUserProfile(createProfileDTO, transactionalEntityManager);
            identifiers = await this.identifierService.createIdentifier(profile, createProfileDTO
                , transactionalEntityManager);
});

What is the best way to unit test the above code?

1

1 Answers

2
votes

I ended up using a Connection object instead of decorators

@InjectConnection()
private readonly connection: Connection)

then make calls to all services like so

await this.connection.transaction(async transactionalEntityManager => {
                try {
                    urDTOCreated = await this.myService1.createSomething(urDTO, transactionalEntityManager);
                    typeDTOCreated = await this.myService2.createSomethingElse(obj1, obj2, transactionalEntityManager);
                }
                catch (ex) {
                    Logger.log(ex);
                    throw new InternalServerErrorException("Error saving data to database");
                }

With that, you can test your services independently and can test your controller as well for managed transaction