NestJS中多类继承复用实体公共列方案失效,求技术解决方案
解决Nest+TypeORM实体类多继承复用公共列的问题
你的mixin方案不生效的核心原因是:TypeORM的装饰器依赖Reflect Metadata存储类的元数据,而你手动复制原型方法的操作并没有拷贝这些元数据,导致TypeORM无法识别BaseModel和AuditModel中的列定义、生命周期钩子等配置。
下面是两种可行的解决方案:
方案一:修复Mixin函数(支持动态组合多个基类)
修改你的mixin函数,在复制原型属性的同时,同步拷贝TypeORM所需的元数据:
import 'reflect-metadata'; // 支持拷贝元数据的mixin函数 function mixin(...baseClasses: any[]): any { class MixedClass {} baseClasses.forEach(baseClass => { // 1. 拷贝原型上的方法和属性 Object.getOwnPropertyNames(baseClass.prototype).forEach(name => { MixedClass.prototype[name] = baseClass.prototype[name]; }); // 2. 拷贝类级别的元数据(比如@Entity、@Column的配置) const classMetadataKeys = Reflect.getMetadataKeys(baseClass); classMetadataKeys.forEach(key => { const metadata = Reflect.getMetadata(key, baseClass); Reflect.defineMetadata(key, metadata, MixedClass); }); // 3. 拷贝原型上的元数据(比如@BeforeInsert、@BeforeUpdate的钩子) const protoMetadataKeys = Reflect.getMetadataKeys(baseClass.prototype); protoMetadataKeys.forEach(key => { const metadata = Reflect.getMetadata(key, baseClass.prototype); Reflect.defineMetadata(key, metadata, MixedClass.prototype); }); }); return MixedClass; }
注意事项:
- 确保项目已安装
reflect-metadata包,并在入口文件(如main.ts)中导入:import 'reflect-metadata'; - 删除
AuditModel中的@PrimaryGeneratedColumn(与BaseModel的id重复,会导致数据库字段冲突)
修改后的AuditModel:
import { Exclude } from "class-transformer"; import { RequestContext } from "src/utils/req-ctx"; import { BeforeInsert, BeforeUpdate, Column } from "typeorm"; export class AuditModel { @Column({ name: "created_by", default: null }) created_by: string @Column({ name: "modified_by", default: null }) modified_by: string @BeforeInsert() setAuditsBeforeInsert() { if (RequestContext.currentRequest?.currentUser) { this.created_by = this.modified_by = RequestContext.currentRequest.currentUser.name } } @BeforeUpdate() setAuditsBeforeUpdate() { if (RequestContext.currentRequest?.currentUser) { this.modified_by = RequestContext.currentRequest.currentUser.name } } }
使用方式不变:
import { Entity, Unique, Column } from 'typeorm'; import { BaseModel } from 'src/base-models/base-model'; import { AuditModel } from 'src/base-models/audit-model'; @Entity() @Unique(['email']) export class Users extends mixin(BaseModel, AuditModel) { @Column() email: string; // 其他用户属性... }
方案二:创建组合基类(适合固定组合场景)
如果你的实体类大多需要同时继承BaseModel和AuditModel,可以直接创建一个组合了两者功能的基类,避免动态mixin的复杂度:
import { PrimaryGeneratedColumn } from "typeorm"; import { BeforeInsert, BeforeUpdate, Column } from "typeorm"; import { RequestContext } from "src/utils/req-ctx"; export class BaseAuditModel { @PrimaryGeneratedColumn('uuid') id: string @Column({ name: "created_by", default: null }) created_by: string @Column({ name: "modified_by", default: null }) modified_by: string @BeforeInsert() setAuditsBeforeInsert() { if (RequestContext.currentRequest?.currentUser) { this.created_by = this.modified_by = RequestContext.currentRequest.currentUser.name } } @BeforeUpdate() setAuditsBeforeUpdate() { if (RequestContext.currentRequest?.currentUser) { this.modified_by = RequestContext.currentRequest.currentUser.name } } }
然后实体类直接继承这个基类:
import { Entity, Unique, Column } from 'typeorm'; import { BaseAuditModel } from 'src/base-models/base-audit-model'; @Entity() @Unique(['email']) export class Users extends BaseAuditModel { @Column() email: string; // 其他用户属性... }
两种方案都能解决你的问题,方案一适合需要灵活组合多个不同基类的场景,方案二更简洁易维护,适合固定组合的需求。
内容的提问来源于stack exchange,提问作者user20181423
相关产品推荐
相关产品推荐

