NestJS中TypeORM PostgreSQL @ManyToOne保存违反非空约束问题
问题原因
你在所有实体的关联关系上错误添加了primary: true配置,该配置的作用是将关联外键设为实体复合主键的一部分,而你的三个实体本身都已经通过@PrimaryGeneratedColumn声明了独立的自增主键,冲突的主键配置导致TypeORM处理关联字段映射时逻辑混乱。
差异化表现的原因
Document到Page的关联能正常运行,是因为你在DocumentEntity的@OneToMany关联上额外配置了cascade: true,保存Page实体时TypeORM会自动处理关联Document的主键映射;而Page到Word的关联没有配置cascade,加上错误的primary: true配置,导致TypeORM没有正确将你赋值的page实体的id映射到数据库的pageId字段,最终插入时pageId为空触发非空约束报错。
解决方案
- 移除所有关联关系上不必要的
primary: true配置,你的场景不需要将关联字段设为主键的一部分。
修改后的实体关联配置参考如下:
document.entity.ts 调整部分
@OneToMany(() => PageEntity, (page) => page.document, { eager: true, cascade: true, }) public pages?: PageEntity[];
page.entity.ts 调整部分
@OneToMany(() => WordEntity, (word) => word.page, { eager: true, onDelete: 'CASCADE', }) words?: WordEntity[]; @ManyToOne(() => DocumentEntity, { onDelete: 'CASCADE', }) @JoinColumn() public document: DocumentEntity;
word.entity.ts 调整部分
@ManyToOne(() => PageEntity, { nullable: true, onDelete: 'CASCADE', }) @JoinColumn() public page!: PageEntity;
- 同步数据库表结构:修改实体配置后需要重建表或者执行迁移更新表约束,旧表残留的非空约束依然会导致报错。
- (可选)代码优化:不需要查询完整的Page实体即可完成关联赋值,可以直接通过id关联,减少一次数据库查询:
async postWord(pageId: number, word: { text: string }) { const wordEntity = new WordEntity(); wordEntity.text = word.text; wordEntity.page = { id: pageId } as PageEntity; await this.wordRepository.save(wordEntity); }
内容的提问来源于stack exchange,提问作者Pierre_T
相关产品推荐
相关产品推荐

