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

NestJS+TypeORM如何默认排除关联子表已软删除的父行?

解决方案:NestJS + TypeORM 软删除关联过滤

核心原因

你之前用child: Not(IsNull())无效,是因为软删除的子实体并未从数据库中删除,只是deletedAt字段被赋值,父表关联的child字段并非null,只是该子实体的deletedAt有值,所以这个判断逻辑不生效。

内置实现方案

1. 直接在查询条件中过滤子表软删除状态

在查询父表时,直接通过关联字段的deletedAt条件过滤,只匹配未被软删除的子实体:

// 查询所有关联未软删除子实体的父表数据
const parents = await this.parentRepository.find({
  where: {
    child: {
      deletedAt: IsNull()
    }
  },
  relations: ['child'] // 按需关联子表
});

如果是一对多关联(父表对应多个子表行),要排除所有子行都被软删除的父表数据,可使用QueryBuilder的HAVING子句:

const parents = await this.parentRepository.createQueryBuilder('parent')
  .leftJoin('parent.children', 'child')
  .groupBy('parent.id')
  .having('COUNT(child.id) > 0 AND SUM(CASE WHEN child.deletedAt IS NOT NULL THEN 1 ELSE 0 END) = 0')
  .getMany();

2. 定义关联时设置默认过滤条件

在父实体的关联字段上,直接添加默认的软删除过滤规则,每次加载关联数据时自动排除已软删除的子实体:

// Parent.entity.ts
@Entity()
export class Parent {
  // ... 其他字段

  // 一对一关联示例
  @OneToOne(() => Child, {
    eager: true, // 按需开启自动加载
    where: { deletedAt: IsNull() } // 关联时默认过滤软删除子实体
  })
  child: Child;

  // 一对多关联示例
  @OneToMany(() => Child, child => child.parent, {
    where: { deletedAt: IsNull() }
  })
  children: Child[];
}

这样查询父表时,关联的子实体只会包含未被软删除的行;若父表对应的子实体全被软删除,该父行因关联条件不匹配不会被查询出来。

3. 全局默认过滤:使用实体订阅者

如果需要所有父表查询都自动应用该过滤规则,无需手动写条件,可通过Entity Subscriber实现全局拦截:

// parent.subscriber.ts
import { EntitySubscriberInterface, EventSubscriber, BeforeFind } from 'typeorm';
import { Parent } from './parent.entity';

@EventSubscriber()
export class ParentSubscriber implements EntitySubscriberInterface<Parent> {
  listenTo() {
    return Parent;
  }

  @BeforeFind()
  beforeFind(queryBuilder) {
    // 自动添加子表软删除过滤条件,一对多关联需调整为 leftJoin('parent.children', 'child')
    queryBuilder.leftJoin('parent.child', 'child').andWhere('child.deletedAt IS NULL');
  }
}

然后在Module中注册该订阅者:

@Module({
  imports: [
    TypeOrmModule.forFeature([Parent, Child]),
    TypeOrmModule.forRoot({
      // ... 数据库配置
      subscribers: [ParentSubscriber] // 注册订阅者
    })
  ]
})
export class AppModule {}

注意事项

  • 确保子实体已正确添加软删除字段:
    // Child.entity.ts
    @DeleteDateColumn()
    deletedAt: Date;
    
  • 使用QueryBuilder时,注意关联表的别名要和条件中的别名保持一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 07:40:01