likes
comments
collection
share

Typeorm-SelectQueryBuilder在使用from子查询时会绑定对应实体表解决方案

作者站长头像
站长
· 阅读数 41

一、简要介绍

Typeorm是使用node进行服务端开发时,用于与数据库打交道比较常用的orm库之一。Typeorm封装了很多API供开发者便捷的进行数据库操作。其中一个比较常用的对象就是Repository对象,它与一个实体表进行关联,因此通过这个对象,可以便捷的操作对应的实体表。

二、问题描述

现在假如存在一个Repository关联了实体表Task。现在存在一个需求需要将Form子查询的结果作为主查询的数据源。简要示例代码如下:

const builder = this.taskRepository
  .createQueryBuilder()
  .select('main_task.*')
  .addSelect(formats)
  .from((subQuery) => {
    // 子查询筛选
    const sub = subQuery
      .select('sub_task.*')
      .from(Task, 'sub_task')
      .where(`sub_task.userId = ${userId}`)
      .andWhere(`sub_task.planStartDate <= '${condition.end}'`)
      .andWhere(`sub_task.planEndDate >= '${condition.start}'`);
    return sub;
  }, 'main_task')
  .andWhere(`main_task.status = '${status === 1}'`)

这个查询很好懂,子查询查询出一个集合A,然后在这个集合A中筛选满足状态的数据。但筛选的结果可能会存在2份,即同一个数据会返回2条。

检查生成的SQL语句后,很容易发现问题:

SELECT main_task.*, DATE_FORMAT(main_task.planStartDate, '%Y-%m-%d')  planStartDate, DATE_FORMAT(main_task.planEndDate, '%Y-%m-%d')  planEndDate, DATE_FORMAT(main_task.realDate, '%Y-%m-%d')  realDate FROM `task` `Task`, (SELECT sub_task.* FROM `task` `sub_task` WHERE `sub_task`.`userId` = 1 AND `sub_task`.`planStartDate` <= '2023-06-13' AND `sub_task`.`planEndDate` >= '2023-06-13') `main_task`

主查询中,Form语句后面不仅存在子查询语句,还存在Task实体表。这样被查询的2个表组成了一个联表,因此查询结果可能会返回2份。这儿不确定是不是Repository对象的设计目的之一就是要固定绑定Form实体表,即便有指定的from方法,但这显示不是我的本意。

Task实体表不是我们添加的,它在这个查询中不应该存在。通过在git上和stackoverflow去查看相关的问题,找到了相关的解决方案。

三、解决方案

一个Repository对象会和一个实体表关联,因此通过Repository对象创建SelectQueryBuilder进行Select查询操作时,会自动在Form后面添加对应实体表。因此解决方案就是可以通过EntityManager对象去创建SelectQueryBuilder对象,这样就没有与任何实体表关联。

示例代码如下:

const builder = this.taskRepository.manager // 使用manager对象创建对象
  .createQueryBuilder()
  .select('main_task.*')
  .addSelect(formats)
  .from((subQuery) => {
    // 子查询筛选
    const sub = subQuery
      .select('sub_task.*')
      .from(Task, 'sub_task')
      .where(`sub_task.userId = ${userId}`)
      .andWhere(`sub_task.planStartDate <= '${condition.end}'`)
      .andWhere(`sub_task.planEndDate >= '${condition.start}'`);
    return sub;
  }, 'main_task')
  .andWhere(`main_task.status = '${status === 1}'`)
转载自:https://juejin.cn/post/7244075827355992121
评论
请登录