如何在Sequelize+TypeScript中实现类似@Embedded的嵌入类功能?
在Sequelize+TypeScript中实现类似JPA @Embedded的属性封装
Sequelize本身没有提供类似Java JPA @Embedded的直接注解,但可以通过**TypeScript访问器(get/set)**结合普通类/接口来实现非实体类的属性封装,以下是具体实现方案:
步骤1:定义非实体的Hobby类型
将Hobby改为普通TypeScript类或接口,不需要继承Model和添加@Table注解(因为它不是独立的数据库实体):
方式1:使用类(支持构造函数)
// Hobby.ts export class Hobby { hobby: string; skillLevel: number; constructor(hobby: string, skillLevel: number) { this.hobby = hobby; this.skillLevel = skillLevel; } }
方式2:使用接口(轻量型)
// Hobby.ts export interface Hobby { hobby: string; skillLevel: number; }
步骤2:修改User类实现封装
在User类中保留对应数据库字段的@Column注解,通过访问器将hobby和skill_level字段封装为Hobby对象:
// User.ts import { Hobby } from './Hobby'; import { Phone } from './Phone'; import { Column, DataType, HasMany, Model, Table } from 'sequelize-typescript'; @Table({ tableName: 'user_test', timestamps: false }) export class User extends Model<User> { @Column({ primaryKey: true, autoIncrement: true, field: 'id', defaultValue: true, }) id: number; @Column({ field: 'name', type: DataType.STRING }) name: string; @Column({ field: 'age', type: DataType.INTEGER }) age: number; // 私有字段对应数据库表的原始字段 @Column({ field: 'hobby', type: DataType.STRING }) private _hobby: string; @Column({ field: 'skill_level', type: DataType.INTEGER }) private _skillLevel: number; // 封装为Hobby对象的访问器 get hobby(): Hobby { // 如果用类:return new Hobby(this._hobby, this._skillLevel); // 如果用接口: return { hobby: this._hobby, skillLevel: this._skillLevel }; } set hobby(hobbyObj: Hobby) { this._hobby = hobbyObj.hobby; this._skillLevel = hobbyObj.skillLevel; } @HasMany(() => Phone) phone: Phone[]; }
使用示例
查询时获取封装对象:
const user = await User.findByPk(1); console.log(user.hobby.hobby); // 直接访问封装后的属性 console.log(user.hobby.skillLevel);设置时直接赋值Hobby对象:
const user = new User(); user.hobby = new Hobby('篮球', 5); // 类方式 // 或接口方式:user.hobby = { hobby: '足球', skillLevel: 4 }; await user.save();
这种方式既保留了数据库字段的映射关系,又实现了属性的逻辑封装,完全符合需求。
内容的提问来源于stack exchange,提问作者Juan Enrique Riquelme
相关产品推荐
相关产品推荐

