You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.

Fixing the beforeUpdate Method's save() Issue

First, let’s spot the immediate bugs and improvements in your code:

  1. Undefined repository variable: You’re referencing repository but never defined it — you meant userRepository instead. That’s a simple typo that would break the query.
  2. Unnecessary await on getRepository(): event.manager.getRepository() is a synchronous method; no need to await it.
  3. Misuse of andWhereInIds: If updatedById is a single user ID (not an array), use findOneBy() directly instead of building a query builder — it’s cleaner and avoids unexpected behavior with single values in IN clauses.
  4. Potential missing user check: If event.entity.updatedById points to a non-existent user, result will be null, which would cause errors when setting log.updatedBy. Always add a guard clause here.
  5. Relationship mapping (if applicable): If AuditLog has a ManyToOne relationship to User, assign the full User entity to log.updatedBy instead 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);
}
Using Repositories in @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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 17:32:46