NestJS中TypeORM@AfterLoad()、@BeforeUpdate()及订阅者中使用Repository的方法与save()无效问题求助
Let’s tackle your two main issues: fixing the broken save() call in your beforeUpdate method, and understanding how to use repositories within @AfterLoad() and @BeforeUpdate() decorators.
beforeUpdate Method's save() Issue First, let’s spot the immediate bugs and improvements in your code:
- Undefined
repositoryvariable: You’re referencingrepositorybut never defined it — you meantuserRepositoryinstead. That’s a simple typo that would break the query. - Unnecessary
awaitongetRepository():event.manager.getRepository()is a synchronous method; no need to await it. - Misuse of
andWhereInIds: IfupdatedByIdis a single user ID (not an array), usefindOneBy()directly instead of building a query builder — it’s cleaner and avoids unexpected behavior with single values inINclauses. - Potential missing user check: If
event.entity.updatedByIdpoints to a non-existent user,resultwill benull, which would cause errors when settinglog.updatedBy. Always add a guard clause here. - Relationship mapping (if applicable): If
AuditLoghas aManyToOnerelationship toUser, assign the fullUserentity tolog.updatedByinstead of a partial object — TypeORM expects the entity instance for relationship fields.
Here’s the corrected version of your beforeUpdate method:
async beforeUpdate(event: UpdateEvent<any>) { const userRepository = event.manager.getRepository(User); // Fetch the user using the updatedById value const updatedByUser = await userRepository.findOneBy({ id: event.entity.updatedById }); // Guard against missing user if (!updatedByUser) { throw new Error(`User with ID ${event.entity.updatedById} not found`); } const log = new AuditLog(); log.before = event.databaseEntity; log.after = event.entity; log.entity = event.metadata.tableName.toString(); log.date = new Date(); log.eventType = EventType.UPDATE; // Assign the full User entity if using a relationship, or keep the partial object if it's a JSON field log.updatedBy = updatedByUser; const logRepository = event.manager.getRepository(AuditLog); // This save() should now work as expected await logRepository.save(log); }
@BeforeUpdate() and @AfterLoad() Let’s break down how to access repositories in each lifecycle hook:
For @BeforeUpdate() (and similar hooks like @BeforeInsert(), @BeforeRemove())
These hooks receive an event object (like UpdateEvent) that includes an EntityManager (event.manager). This manager is tied to the current transaction context, so you should use it to fetch repositories instead of injecting a global repository. This ensures all operations are part of the same transaction.
Key points:
- Use
event.manager.getRepository(EntityClass)(synchronously) to get the repository. - All operations using this manager will participate in the same transaction as the update/insert/remove operation.
For @AfterLoad()
The @AfterLoad() decorator on an entity method doesn’t receive any event parameters, so you can’t access the EntityManager directly here. Additionally, entities aren’t dependency-injected in NestJS/TypeORM, so you can’t inject a repository into the entity class itself.
The cleanest solution is to use a TypeORM Subscriber instead of the entity-level @AfterLoad() decorator. Subscribers are dependency-injected, so you can inject repositories or the EntityManager directly.
Here’s an example subscriber for handling AfterLoad events:
import { Injectable } from '@nestjs/common'; import { EntitySubscriberInterface, EventSubscriber, AfterLoad, EntityManager } from 'typeorm'; import { YourEntity } from './your-entity.entity'; import { UserRepository } from './user.repository'; @Injectable() @EventSubscriber() export class YourEntitySubscriber implements EntitySubscriberInterface<YourEntity> { constructor( private readonly userRepository: UserRepository, private readonly entityManager: EntityManager, ) {} // Specify which entity this subscriber listens to listenTo() { return YourEntity; } async afterLoad(entity: YourEntity) { // Use the injected repository to fetch related data const relatedUser = await this.userRepository.findOneBy({ id: entity.createdById }); // Attach the data to the entity for use in your application entity.createdByUser = relatedUser; // Or use the EntityManager for more general operations const otherEntity = await this.entityManager.findOneBy(OtherEntity, { id: entity.otherId }); entity.relatedOtherEntity = otherEntity; } }
Don’t forget to add this subscriber to your module’s providers array so NestJS can register it with TypeORM:
@Module({ providers: [YourEntitySubscriber, UserRepository], }) export class YourModule {}
内容的提问来源于stack exchange,提问作者ehsan mandegar

