You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 10:46:28