Слушатели и подписчики сущностей
Эта страница переведена PageTurner AI (бета). Не одобрена официально проектом. Нашли ошибку? Сообщить о проблеме →
Что такое слушатель сущности?
Любая ваша сущность может содержать методы с пользовательской логикой, которые отслеживают определённые события сущности. Эти методы должны быть помечены специальными декораторами в зависимости от события, которое вы хотите отслеживать.
Примечание: Не выполняйте запросы к базе данных внутри слушателя, вместо этого используйте подписчиков.
@AfterLoad
Вы можете определить метод с любым именем в сущности и пометить его @AfterLoad.
TypeORM будет вызывать его каждый раз при загрузке сущности
через QueryBuilder или методы find репозитория/менеджера.
Пример:
@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 будет вызывать его после восстановления сущности через 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)
}
}
Убедитесь, что свойство subscribers указано в ваших DataSourceOptions, чтобы TypeORM загружал ваших подписчиков.
Event Object
За исключением listenTo, всем методам EntitySubscriberInterface передаётся объект события со следующими базовыми свойствами:
-
dataSource: DataSource- Источник данных, используемый в событии. -
queryRunner: QueryRunner- QueryRunner, используемый в транзакции события. -
manager: EntityManager- EntityManager, используемый в транзакции события.
Дополнительные свойства смотрите в каждом интерфейсе событий.
Обратите внимание, что event.entity может не содержать первичные ключи при использовании Repository.update(). Будут доступны только значения из частичного объекта сущности. Чтобы обеспечить наличие первичных ключей в подписчиках, явно передавайте их значения в частичном объекте сущности или используйте 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' }
}
Примечание: Все операции с базой данных в подписанных обработчиках событий должны выполняться через экземпляр queryRunner или manager из объекта события.