NestJS + TypeORM 实体数据库操作审计选型与实现疑问
NestJS 实体数据库操作审计方案:Listener vs Subscriber
一、Listener 实现(基于实体继承的公共审计类)
如果想通过实体继承复用审计逻辑,可以创建一个整合时间属性与审计钩子的抽象基类,需要审计的实体直接继承该类即可。
1. 创建带审计钩子的抽象基类
import { AfterInsert, BaseEntity } from 'typeorm'; import TimeProperty from './time-property'; // 整合时间属性与审计逻辑的抽象基类 export abstract class AuditableEntity extends TimeProperty { @AfterInsert() async handleAfterInsert() { // 编写插入后的审计逻辑,比如记录操作日志、关联操作用户等 console.log(`实体 ${this.constructor.name} 已插入,ID:${(this as BaseEntity).id}`); // 示例:结合请求上下文获取当前用户(需自行实现请求上下文工具) // const currentUser = getCurrentUser(); // this.createdBy = currentUser.id; // await this.save(); } }
2. 业务实体继承基类
需要审计的实体直接继承AuditableEntity,自动拥有时间字段与审计逻辑:
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; import { AuditableEntity } from './auditable-entity'; @Entity() export class Product extends AuditableEntity { @PrimaryGeneratedColumn() id: number; @Column() name: string; // 自动继承created_time、updated_time字段,以及AfterInsert审计钩子 }
二、Subscriber 实现(单文件监听部分实体)
如果想集中管理审计逻辑,且仅监听继承TimeProperty的实体,可以创建一个全局Subscriber,在事件钩子中通过类型判断筛选目标实体。
1. 创建全局审计Subscriber
import { EntitySubscriberInterface, EventSubscriber, InsertEvent, UpdateEvent, DeleteEvent, } from 'typeorm'; import TimeProperty from './time-property'; @EventSubscriber() export class AuditSubscriber implements EntitySubscriberInterface { // 监听所有实体,后续通过类型判断过滤目标 listenTo() { return Object; } // 插入后审计 async afterInsert(event: InsertEvent<any>) { if (event.entity instanceof TimeProperty) { console.log(`插入审计:${event.entity.constructor.name},ID:${event.entity.id}`); // 这里可添加具体审计操作,比如写入独立的审计日志表 } } // 更新后审计 async afterUpdate(event: UpdateEvent<any>) { if (event.entity instanceof TimeProperty) { console.log(`更新审计:${event.entity.constructor.name},ID:${event.entity.id}`); } } // 删除后审计 async afterDelete(event: DeleteEvent<any>) { if (event.entity instanceof TimeProperty) { console.log(`删除审计:${event.entity.constructor.name},ID:${event.entity.id}`); } } }
2. 注册Subscriber到NestJS
在app.module.ts中,将Subscriber配置到TypeOrmModule:
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { AuditSubscriber } from './audit.subscriber'; import { Product } from './product.entity'; @Module({ imports: [ TypeOrmModule.forRoot({ // 数据库连接配置 type: 'postgres', host: 'localhost', port: 5432, username: 'postgres', password: 'password', database: 'test', entities: [Product], subscribers: [AuditSubscriber], // 注册全局审计Subscriber synchronize: true, }), TypeOrmModule.forFeature([Product]), ], }) export class AppModule {}
方案选择建议
- Listener:适合审计逻辑与实体强绑定、希望通过继承快速复用的场景,代码分散但实体层面更直观。
- Subscriber:适合集中管理所有审计规则、无需修改实体代码的场景,便于统一调整审计策略。
内容的提问来源于stack exchange,提问作者Abhimanyu Patil
相关产品推荐
相关产品推荐

