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

TypeORM中软删除父实体后如何避免子实体被软删并正常查询

问题根源与解决步骤

首先,你添加的onDelete和orphanedRowAction配置没生效,是因为没放在关联装饰器的选项参数里。另外,TypeORM的软删除(通过@DeleteDateColumn)本身不会自动级联软删子实体——你看到的子实体"被软删",大概率是查询时被关联的父实体软删过滤器给过滤掉了,而非子实体真的被标记了deletedAt。

1. 修正实体关联配置

把数据库级别的关联配置放到@OneToMany和@ManyToOne的第三个参数里:

class Parent extends BaseEntity{
    @Column()
    name:string

    @OneToMany(
        () => Child,
        (child) => child.parent,
        {
            onDelete: "NO ACTION", // 硬删父实体时,数据库不做级联操作(软删不触发这个)
            orphanedRowAction: "nullify" // 硬删父实体时,将子实体的parent外键设为null
        }
    )
    children: Child[]

    @DeleteDateColumn()
    deletedAt?: Date;
}

class Child extends BaseEntity{
    @Column()
    name:string

    @ManyToOne(
        () => Parent,
        (parent) => parent.children,
        {
            onDelete: "NO ACTION" // 对应父实体的配置,硬删时不级联
        }
    )
    parent: Parent
}

2. 确保软删除父实体的方式正确

软删除父实体必须用softDelete或softRemove方法,不能用delete或remove(后者是硬删除,会触发数据库的onDelete规则):

// 正确的软删方式
await Parent.softDelete(parentId);
// 或者
const parent = await Parent.findOneBy({ id: parentId });
await Parent.softRemove(parent);

3. 查询子实体时,避免被父实体的软删过滤器过滤

默认情况下,当你关联查询子实体和父实体时,TypeORM会自动过滤掉已软删的父实体,但子实体本身并没有被软删。如果要查询所有子实体(无论父实体是否被软删),可以用以下两种方式:

方式一:用find方法
const children = await Child.find({
    relations: ["parent"],
    // 允许加载已软删的父实体
    withDeleted: { parent: true }
});
方式二:用createQueryBuilder
const children = await getConnection()
    .createQueryBuilder(Child, "child")
    // 左连接父实体,不自动过滤软删的父实体
    .leftJoinAndSelect("child.parent", "parent")
    // 如果子实体本身没有软删字段,可去掉这行
    .where("child.deletedAt IS NULL")
    .getMany();

这样操作后,软删父实体时,子实体的deletedAt不会被修改,查询子实体也能正常返回,不受父实体软删状态影响。

内容的提问来源于stack exchange,提问作者Amir Makram

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 18:45:50