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

一、简要介绍

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}'`)

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MY49zqju' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片