Search code examples
typescripttypeorm

TypeORM - Using transactions in Listener methods (BeforeUpdate)


I have a NodeJS backend server using TypeORM, and I need to perform an insert every time an entity is updated. So I have the following code in my BaseModel class:

abstract class BaseModel {
// ...
  @BeforeUpdate()
  private async InsertBeforeUpdate() {
    let entToSave: BaseModel;
    // Create the entity that I want to insert
    await getManager().save(entToSave);
  }
}

Then, in my DAL:

const saveUser = (user: User) => {
  return new Promise((resolve, reject) => {
    getManager().transaction(async manager => {
      manager
        .save(user)
        .then(() => {
          resolve('yay');
        })
        .catch(() => {
          reject(new Error('boo'));
        });
    });
  });
};

However, this raises a problem. If the save operation fails and the saveUser promise rejects, the insert performed in @BeforeUpdate doesn't exist on the same transaciton, and will save to the DB.

How can I access said transactional manager in the @BeforeUpdate listener function?


Solution

  • You can use a Subscriber instead of a Listener, you can find more information on the TypeORM documentation on subscribers. Then you should add the subscriber to your connectionOptions (see config here)

    For example, to transform your current hook into a subscriber, you can declare it as follows:

    @EventSubscriber()
    export class UserSubscriber implements EntitySubscriberInterface<User> {
    
        listenTo() {
            return User;
        }
    
        async beforeUpdate(event: UpdateEvent<Person>) {
            const entToSave = new WhateverEntity();
            // This will give you access to original manager, and so same transaction
            await event.manager
              .save(entToSave);
        }
    }