Nest.js+TypeORM+PostgreSQL多对多中间表加字段重启后数据丢失问题
问题根源
你当前的实现存在两个冲突点:
- 同时使用了
@ManyToMany自动托管中间表 + 自定义中间表实体两种模式,TypeORM默认的多对多关联不会处理中间表的额外字段,创建关联时只会插入两个关联id,导致count字段为null - 你大概率开启了TypeORM的
synchronize: true配置,每次服务重启时会用@ManyToMany自动生成的无count字段的中间表结构覆盖现有表,导致手动写入的count值被清空
修复步骤
1. 重构实体关联,将多对多拆分为两个一对多
调整product.entity.ts
把原来的多对多关联替换为和中间表的一对多关联:
@Entity() export class Product extends BaseEntity { @PrimaryGeneratedColumn() id: number; // 替换原来的ManyToMany关联,关联自定义中间表 @OneToMany(() => ProductStone, productStone => productStone.product, { cascade: true // 开启级联,创建产品时自动保存中间表数据 }) productStones: ProductStone[]; }
调整stone.entity.ts
同样补充和中间表的一对多关联:
@Entity() export class Stone extends BaseEntity { @PrimaryGeneratedColumn() id: number; @Column() title: string; @OneToMany(() => ProductStone, productStone => productStone.stone) productStones: ProductStone[]; }
调整product_stone.entity.ts
补充和两个主表的多对一关联,复合主键可保留:
@Entity('product_stone') export class ProductStone extends BaseEntity { // 可根据需求去掉nullable配置设为非空 @Column() count: number; @PrimaryColumn() productId: number; @PrimaryColumn() stoneId: number; // 新增和Product的多对一关联 @ManyToOne(() => Product, product => product.productStones, { onDelete: 'CASCADE' }) product: Product; // 新增和Stone的多对一关联 @ManyToOne(() => Stone, stone => stone.productStones, { onDelete: 'CASCADE' }) stone: Stone; }
2. 调整创建产品的业务逻辑
不能再直接传入Stone数组赋值,需要组装中间表实例:
// 假设接收的参数是createProductDto,里面的stones结构为[{id:1, count:1}, ...] async create(createProductDto) { const product = new Product(); // 赋值产品其他基础字段 // ... // 组装中间表关联数据 product.productStones = createProductDto.stones.map(stoneItem => { const productStone = new ProductStone(); productStone.stoneId = stoneItem.id; productStone.count = stoneItem.count; return productStone; }); return await product.save(); }
3. 调整TypeORM配置(可选但推荐)
开发阶段确认实体结构稳定后,可将synchronize改为false,用迁移(Migration)管理表结构变更,避免重启服务时自动覆盖表数据。生产环境必须关闭synchronize配置。
内容的提问来源于stack exchange,提问作者AmirChegini
相关产品推荐
相关产品推荐

