NestJS使用TypeORM查询一对多属性报Cannot query across one-to-many错误如何解决
TypeORM 一对多关联筛选报错解决方案
问题背景
存在两个关联实体,分别是 car 和 carAvailability,Car 实体定义如下:
import { Entity, Column, PrimaryGeneratedColumn, OneToMany } from 'typeorm'; import { CarAvailability } from 'src/car-availabilitys/car-availability.entity'; @Entity('cars') export class Car { @PrimaryGeneratedColumn() id: number; @Column() name: string; @OneToMany(() => CarAvailability, (carAvailability) => carAvailability.car, { eager: true, cascade: true, }) availabilities: CarAvailability[]; }
需求为根据可用时间筛选符合条件的车辆,先后尝试的两种实现方案均触发报错。
报错原因分析
方案1报错原因
方案1代码:
async test () { const startDateTime = '2012-04-24 02:25:43.511'; return await this.repo.find({ relations: ['availabilities'], where: { availabilities: { start_date_time: startDateTime } } }); }
报错信息:Error: Cannot query across one-to-many for property availabilities
原因:0.2.x及更早版本的TypeORM不支持直接在find方法的where条件中嵌套一对多关联的属性筛选,跨一对多关联查询需要使用子查询或QueryBuilder的关联条件写法。
方案2报错原因
方案2代码:
async test () { const startDateTime = '2012-04-24 02:25:43.511'; return this.repo.createQueryBuilder('cars') .innerJoin('cars.availabilities', 'car_availabilities') .where("cars.availabilities.start_date_time = :startDateTime", { startDateTime }) .getMany(); }
报错信息:QueryFailedError: missing FROM-clause entry for table "availabilities"
原因:已经给
cars.availabilities关联定义了别名car_availabilities,where条件中需要使用别名访问字段,不能继续使用原关联路径cars.availabilities访问。
可行解决方案
方案A:高版本TypeORM(0.3.x+)find方法实现
如果TypeORM版本已升级到0.3.x及以上,直接调整find方法的relations写法即可正常查询:
async test () { const startDateTime = '2012-04-24 02:25:43.511'; return await this.repo.find({ relations: { availabilities: true }, where: { availabilities: { start_date_time: startDateTime } } }); }
方案B:全版本兼容的QueryBuilder实现
无需升级版本,修改原有QueryBuilder的where条件即可:
async test () { const startDateTime = '2012-04-24 02:25:43.511'; return this.repo.createQueryBuilder('cars') .innerJoinAndSelect('cars.availabilities', 'car_availabilities') .where("car_availabilities.start_date_time = :startDateTime", { startDateTime }) .getMany(); }
如果需要保留车辆所有的availabilities数据(仅筛选符合条件的车辆,不过滤关联的可用时间列表),可以将筛选逻辑放在子查询中:
async test () { const startDateTime = '2012-04-24 02:25:43.511'; return this.repo.createQueryBuilder('cars') .leftJoinAndSelect('cars.availabilities', 'car_availabilities') .whereExists( qb => qb.select('1') .from(CarAvailability, 'ca') .where('ca.carId = cars.id') .andWhere('ca.start_date_time = :startDateTime', { startDateTime }) ) .setParameter('startDateTime', startDateTime) .getMany(); }
内容的提问来源于stack exchange,提问作者Amirul Iqram
相关产品推荐
相关产品推荐

