跳至主内容区

实体监听器与订阅者

非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

什么是实体监听器?

您可以在任何实体中创建包含自定义逻辑的方法,用于监听特定实体事件。这些方法需要使用特殊装饰器进行标记,具体取决于您要监听的事件类型。

注意: 请勿在监听器内执行任何数据库操作,应改用订阅者

@AfterLoad

您可以在实体中定义任意名称的方法并用 @AfterLoad 标记, TypeORM 将在每次通过 QueryBuilder 或仓库/管理器查询方法加载实体时调用它。 示例:

@Entity()
export class Post {
@AfterLoad()
updateCounters() {
if (this.likesCount === undefined) this.likesCount = 0
}
}

@BeforeInsert

您可以在实体中定义任意名称的方法并用 @BeforeInsert 标记, TypeORM 将在通过仓库/管理器 save 方法插入实体前调用它。 示例:

@Entity()
export class Post {
@BeforeInsert()
updateDates() {
this.createdDate = new Date()
}
}

@AfterInsert

您可以在实体中定义任意名称的方法并用 @AfterInsert 标记, TypeORM 将在通过仓库/管理器 save 方法插入实体后调用它。 示例:

@Entity()
export class Post {
@AfterInsert()
resetCounters() {
this.counters = 0
}
}

@BeforeUpdate

您可以在实体中定义任意名称的方法并使用@BeforeUpdate标记,TypeORM 将在通过仓库/管理器的save方法更新现有实体前自动调用该方法。请注意:仅当模型数据发生变更时才会触发。若执行save时未修改模型数据,则@BeforeUpdate@AfterUpdate不会执行。 示例:

@Entity()
export class Post {
@BeforeUpdate()
updateDates() {
this.updatedDate = new Date()
}
}

@AfterUpdate

您可以在实体中定义任意名称的方法并用 @AfterUpdate 标记, TypeORM 将在通过仓库/管理器 save 方法更新现有实体后调用它。 示例:

@Entity()
export class Post {
@AfterUpdate()
updateCounters() {
this.counter = 0
}
}

@BeforeRemove

你可以在实体中定义一个任意名称的方法,并用 @BeforeRemove 标记。TypeORM 会在实体被仓库/管理器的 remove 方法移除之前调用该方法。 示例:

@Entity()
export class Post {
@BeforeRemove()
updateStatus() {
this.status = "removed"
}
}

@AfterRemove

您可以在实体中定义任意名称的方法并用 @AfterRemove 标记, TypeORM 将在通过仓库/管理器 remove 方法移除实体后调用它。 示例:

@Entity()
export class Post {
@AfterRemove()
updateStatus() {
this.status = "removed"
}
}

@BeforeSoftRemove

你可以在实体中定义一个任意名称的方法,并用 @BeforeSoftRemove 标记。TypeORM 会在实体被仓库/管理器的 softRemove 方法软删除之前调用该方法。 示例:

@Entity()
export class Post {
@BeforeSoftRemove()
updateStatus() {
this.status = "soft-removed"
}
}

@AfterSoftRemove

您可以在实体中定义任意名称的方法并用 @AfterSoftRemove 标记, TypeORM 将在通过仓库/管理器 softRemove 方法软删除实体后调用它。 示例:

@Entity()
export class Post {
@AfterSoftRemove()
updateStatus() {
this.status = "soft-removed"
}
}

@BeforeRecover

你可以在实体中定义一个任意名称的方法,并用 @BeforeRecover 标记。TypeORM 会在实体被仓库/管理器的 recover 方法恢复之前调用该方法。 示例:

@Entity()
export class Post {
@BeforeRecover()
updateStatus() {
this.status = "recovered"
}
}

@AfterRecover

您可以在实体中定义任意名称的方法,并使用 @AfterRecover 标记, TypeORM 会在通过 repository/manager 的 recover 方法恢复实体后调用该方法。 示例:

@Entity()
export class Post {
@AfterRecover()
updateStatus() {
this.status = "recovered"
}
}

什么是订阅者?

将类标记为事件订阅者,可监听特定实体事件或所有实体事件。事件通过QueryBuilder及仓库/管理器的方法触发。 示例:

@EventSubscriber()
export class PostSubscriber implements EntitySubscriberInterface<Post> {
/**
* Indicates that this subscriber only listen to Post events.
*/
listenTo() {
return Post
}

/**
* Called before post insertion.
*/
beforeInsert(event: InsertEvent<Post>) {
console.log(`BEFORE POST INSERTED: `, event.entity)
}
}

您可以实现EntitySubscriberInterface中的任意方法。要监听所有实体事件,只需省略listenTo方法并使用any

@EventSubscriber()
export class PostSubscriber implements EntitySubscriberInterface {
/**
* Called after entity is loaded.
*/
afterLoad(entity: any) {
console.log(`AFTER ENTITY LOADED: `, entity)
}

/**
* Called before query execution.
*/
beforeQuery(event: BeforeQueryEvent<any>) {
console.log(`BEFORE QUERY: `, event.query)
}

/**
* Called after query execution.
*/
afterQuery(event: AfterQueryEvent<any>) {
console.log(`AFTER QUERY: `, event.query)
}

/**
* Called before entity insertion.
*/
beforeInsert(event: InsertEvent<any>) {
console.log(`BEFORE ENTITY INSERTED: `, event.entity)
}

/**
* Called after entity insertion.
*/
afterInsert(event: InsertEvent<any>) {
console.log(`AFTER ENTITY INSERTED: `, event.entity)
}

/**
* Called before entity update.
*/
beforeUpdate(event: UpdateEvent<any>) {
console.log(`BEFORE ENTITY UPDATED: `, event.entity)
}

/**
* Called after entity update.
*/
afterUpdate(event: UpdateEvent<any>) {
console.log(`AFTER ENTITY UPDATED: `, event.entity)
}

/**
* Called before entity removal.
*/
beforeRemove(event: RemoveEvent<any>) {
console.log(
`BEFORE ENTITY WITH ID ${event.entityId} REMOVED: `,
event.entity,
)
}

/**
* Called after entity removal.
*/
afterRemove(event: RemoveEvent<any>) {
console.log(
`AFTER ENTITY WITH ID ${event.entityId} REMOVED: `,
event.entity,
)
}

/**
* Called before entity removal.
*/
beforeSoftRemove(event: SoftRemoveEvent<any>) {
console.log(
`BEFORE ENTITY WITH ID ${event.entityId} SOFT REMOVED: `,
event.entity,
)
}

/**
* Called after entity removal.
*/
afterSoftRemove(event: SoftRemoveEvent<any>) {
console.log(
`AFTER ENTITY WITH ID ${event.entityId} SOFT REMOVED: `,
event.entity,
)
}

/**
* Called before entity recovery.
*/
beforeRecover(event: RecoverEvent<any>) {
console.log(
`BEFORE ENTITY WITH ID ${event.entityId} RECOVERED: `,
event.entity,
)
}

/**
* Called after entity recovery.
*/
afterRecover(event: RecoverEvent<any>) {
console.log(
`AFTER ENTITY WITH ID ${event.entityId} RECOVERED: `,
event.entity,
)
}

/**
* Called before transaction start.
*/
beforeTransactionStart(event: TransactionStartEvent) {
console.log(`BEFORE TRANSACTION STARTED: `, event)
}

/**
* Called after transaction start.
*/
afterTransactionStart(event: TransactionStartEvent) {
console.log(`AFTER TRANSACTION STARTED: `, event)
}

/**
* Called before transaction commit.
*/
beforeTransactionCommit(event: TransactionCommitEvent) {
console.log(`BEFORE TRANSACTION COMMITTED: `, event)
}

/**
* Called after transaction commit.
*/
afterTransactionCommit(event: TransactionCommitEvent) {
console.log(`AFTER TRANSACTION COMMITTED: `, event)
}

/**
* Called before transaction rollback.
*/
beforeTransactionRollback(event: TransactionRollbackEvent) {
console.log(`BEFORE TRANSACTION ROLLBACK: `, event)
}

/**
* Called after transaction rollback.
*/
afterTransactionRollback(event: TransactionRollbackEvent) {
console.log(`AFTER TRANSACTION ROLLBACK: `, event)
}
}

请确保在您的 DataSourceOptions 中设置了 subscribers 属性,这样 TypeORM 才能加载您的订阅者。

Event Object

listenTo 方法外,所有 EntitySubscriberInterface 接口的方法都会接收一个包含以下基础属性的事件对象:

  • dataSource: DataSource - 事件中使用的 DataSource。

  • queryRunner: QueryRunner - 事件事务中使用的 QueryRunner。

  • manager: EntityManager - 事件事务中使用的 EntityManager。

请查看各事件接口获取额外属性信息。

请注意:当使用 Repository.update() 方法时,event.entity 不一定包含主键值。只有实体部分更新中提供的值才可用。若要在订阅者中获取主键,您可以在部分实体对象字面量中显式传递主键值,或改用会执行重新获取操作的 Repository.save() 方法。

await postRepository.update(post.id, { description: "Bacon ipsum dolor amet cow" })

// post.subscriber.ts
afterUpdate(event: UpdateEvent<Post>) {
console.log(event.entity) // outputs { description: 'Bacon ipsum dolor amet cow' }
}

注意: 所有在订阅事件监听器中的数据库操作都应通过事件对象的 queryRunnermanager 实例执行。