TypeORM中{onDelete: "CASCADE"}配合softRemove不生效问题排查
问题:SoftRemove FavoriteEntity时关联的FavoriteHomeworkEntity未被级联软删除
我定义了如下TypeORM实体,原本预期对FavoriteEntity执行softRemove操作时,其关联的所有FavoriteHomeworkEntity也会被软删除,但实际并未生效,请问哪里操作有误?
@Entity() export class FavoriteEntity { @PrimaryGeneratedColumn('uuid') id: string; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; @DeleteDateColumn() deletedAt: Date; @Column({ default: null }) name: string; @ManyToOne(() => UserEntity, (user) => user.favorites) user!: UserEntity; @OneToMany(() => FavoriteHomeworkEntity, (favoriteHomework) => favoriteHomework.favorite) favoriteHomeworks!: Array<FavoriteHomeworkEntity>; homeworksCount: number; constructor(partial: Partial<FavoriteEntity>) { Object.assign(this, partial); } } @Entity() export class FavoriteHomeworkEntity { @PrimaryGeneratedColumn('uuid') id: string; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; @DeleteDateColumn() deletedAt: Date; @ManyToOne(() => FavoriteEntity, (favorite) => favorite.favoriteHomeworks, {onDelete: "CASCADE"}) favorite!: FavoriteEntity; @ManyToOne(() => HomeworkEntity, (homework) => homework.favoriteHomeworks) homework!: HomeworkEntity; constructor(partial: Partial<FavoriteHomeworkEntity>) { Object.assign(this, partial); } }
原因分析
你配置的{onDelete: "CASCADE"}是数据库级别的硬删除规则,它只在对FavoriteEntity执行remove()(硬删除,直接从数据库删除记录)时生效,会自动删除关联的FavoriteHomeworkEntity记录。但softRemove()是软删除操作,本质只是更新实体的deletedAt字段标记为已删除,并不会触发数据库级别的删除行为,所以这个配置对软删除完全无效。
另外TypeORM默认的cascade选项仅针对保存、更新类操作生效,不包含软删除逻辑,所以不会自动级联处理关联实体的软删除。
解决方法
方法1:使用TypeORM订阅器(推荐)
通过订阅器监听FavoriteEntity的软删除事件,在事件回调中批量更新关联FavoriteHomeworkEntity的deletedAt字段,实现级联软删除:
import { EventSubscriber, EntitySubscriberInterface, SoftRemoveEvent } from "typeorm"; import { FavoriteEntity } from "./favorite.entity"; import { FavoriteHomeworkEntity } from "./favorite-homework.entity"; @EventSubscriber() export class FavoriteSubscriber implements EntitySubscriberInterface<FavoriteEntity> { // 指定监听的实体 listenTo() { return FavoriteEntity; } // 在FavoriteEntity软删除完成后执行 async afterSoftRemove(event: SoftRemoveEvent<FavoriteEntity>) { const targetFavorite = event.entity; if (!targetFavorite) return; // 批量软删除关联的FavoriteHomeworkEntity await event.manager.getRepository(FavoriteHomeworkEntity) .createQueryBuilder() .update() .set({ deletedAt: new Date() }) .where("favoriteId = :favoriteId", { favoriteId: targetFavorite.id }) .execute(); } }
注意:需要在TypeORM配置中注册这个订阅器,或者确保订阅器文件被TypeORM扫描到。
方法2:业务代码中手动处理
在执行softRemove之前,主动查询关联的favoriteHomeworks,逐个软删除后再处理主实体:
async softRemoveFavorite(favoriteId: string) { const favoriteRepo = this.getRepository(FavoriteEntity); // 查询目标收藏夹及其关联的作业收藏 const targetFavorite = await favoriteRepo.findOne({ where: { id: favoriteId }, relations: ["favoriteHomeworks"] }); if (!targetFavorite) return; // 先软删除所有关联的作业收藏 await this.getRepository(FavoriteHomeworkEntity).softRemove(targetFavorite.favoriteHomeworks); // 再软删除收藏夹 await favoriteRepo.softRemove(targetFavorite); }
内容的提问来源于stack exchange,提问作者Kernier
相关产品推荐
相关产品推荐

