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

TypeORM启用Eager Load时如何按条件加载子实体

问题描述

我有Parent与Child两个实体,二者为OneToMany关联关系且已启用eager加载。当前查询Parent实体时会返回所有子实体,我期望仅加载deleted属性为false的Child子实体。尝试修改findAll方法的查询条件为{ where: { deleted: false, children:{deleted:false} } }后,若父实体存在已删除的子实体,则该父实体无法被查询到,寻求可行解决方案。

实体与服务代码

Parent 实体

@Entity()
export class Parent {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ default: false })
  deleted: boolean;

  @OneToMany(() => Child, (child) => child.parent, {
    cascade: true,
    eager: true,
  })
  children: Child[];
}

Child 实体

@Entity()
export class Child{
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ default: false })
  deleted: boolean;

  @ManyToOne(() => Parent, (parent) => parent.children)
  parent: Parent;
}

原 ParentsService 代码

@Injectable()
export class ParentsService {
  constructor(
    @InjectRepository(Parent)
    private parentRepository: Repository<Parent>,
  ) {}

  findAll(): Promise<Parent[]> {
    return this.parentRepository.find({ where: { deleted: false } });
  }
}

尝试过的错误写法

findAll(): Promise<Parent[]> {
  return this.parentRepository.find({ where: { deleted: false, children:{deleted:false} } });
}

解决方案

方案1:用 QueryBuilder 在数据库层面过滤子实体(推荐)

直接使用createQueryBuilder做左关联查询,在关联时过滤子实体,这样父实体不会因为存在已删除子实体而被排除,同时只加载未删除的子实体:

@Injectable()
export class ParentsService {
  constructor(
    @InjectRepository(Parent)
    private parentRepository: Repository<Parent>,
  ) {}

  async findAll(): Promise<Parent[]> {
    return this.parentRepository
      .createQueryBuilder('parent')
      // 关联子实体并过滤未删除的记录
      .leftJoinAndSelect('parent.children', 'child', 'child.deleted = :isDeleted', { isDeleted: false })
      // 过滤未删除的父实体
      .where('parent.deleted = :parentDeleted', { parentDeleted: false })
      .getMany();
  }
}

方案2:内存层面过滤子实体(适合小数据量)

如果子实体数量不多,可以通过以下方式在内存中过滤:

方法A:添加 getter 过滤

修改Parent实体,新增一个getter来返回未删除的子实体:

@Entity()
export class Parent {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ default: false })
  deleted: boolean;

  @OneToMany(() => Child, (child) => child.parent, {
    cascade: true,
    eager: true,
  })
  children: Child[];

  // 仅返回未删除的子实体
  get activeChildren(): Child[] {
    return this.children.filter(child => !child.deleted);
  }
}

使用时直接调用parent.activeChildren获取过滤后的子实体。

方法B:用 @AfterLoad 自动过滤

通过TypeORM的@AfterLoad装饰器,在实体加载完成后自动过滤子实体:

@Entity()
export class Parent {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ default: false })
  deleted: boolean;

  @OneToMany(() => Child, (child) => child.parent, {
    cascade: true,
    eager: true,
  })
  children: Child[];

  @AfterLoad()
  filterActiveChildren() {
    this.children = this.children.filter(child => !child.deleted);
  }
}

这种方式无需修改查询代码,加载后自动处理子实体列表。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 22:32:30