TypeORM postgresql 急切加载关系定义为惰性

p-m*_*wan 7 postgresql typeorm nestjs

我正在尝试找出解决 Nestjs TypeORM postgresql 应用程序中懒惰关系的最佳方法(或最佳实践方法)。

我已经将实体中的一些 OneToMany 和 ManyToOne 关系定义为惰性关系,并且在查询这些实体之一的数组时,到目前为止我发现的最佳解决方案是一大堆承诺 rosolving。

我的Customer实体(customer.entity.ts):

import { Column, CreateDateColumn, Entity, Index, PrimaryGeneratedColumn, UpdateDateColumn, ManyToOne, OneToMany } from 'typeorm';
import { IsEmail } from 'class-validator';
import { ReservationDate } from '../reservation_date/reservation_date.entity';

@Entity()
export class Customer {
    @PrimaryGeneratedColumn('uuid')
    id: string;

    @Index()
    @Column()
    @IsEmail()
    email: string;

    @Column()
    firstName: string;

    @Column()
    lastName: string;

    @CreateDateColumn()
    createDate: Date;

    @UpdateDateColumn()
    updateDate: Date;

    @OneToMany(type => ReservationDate, reservationDate => reservationDate.customer)
    reservationDates: Promise<ReservationDate[]>;
}
Run Code Online (Sandbox Code Playgroud)

和我的ReservationDate实体(reservation_date.entity.ts):

import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn, ManyToOne } from 'typeorm';
import { Customer } from '../customer/customer.entity';

@Entity()
export class ReservationDate {
    @PrimaryGeneratedColumn('uuid')
    id: string;

    @Column()
    date: Date;

    @CreateDateColumn()
    createDate: Date;

    @UpdateDateColumn()
    updateDate: Date;

    @ManyToOne(type => Customer, customer => customer.reservationDates, { onDelete: 'CASCADE' })
    customer: Promise<Customer>;
}
Run Code Online (Sandbox Code Playgroud)

我需要检索一个ReservationDates数组,并将其发送到某个地方,但我需要它来解析该customer字段(例如,预先加载该关系)。这就是“工作”:

const reservationDates: ReservationDate[] = await this.reservationDateRepository
    .createQueryBuilder('reservationDate')
    .leftJoinAndSelect('reservationDate.customer', 'customer')
    .getMany();

// Same result as query builder above
// const reservationDates: ReservationDate[] = await this.reservationDateRepository
//     .find({
//         relations: ['customer'],
//         take: 5
//     });

console.log(reservationDates[0].car);      // => Promise { <pending> }
console.log(reservationDates[0].__car__);  // => Car { id: string, owner... }

// this is where it gets ugly
const reservationDatesWithResolvedRelationships = await Promise.all(
    reservationDates.map(async (resDate: ReservationDate) => {
        const withResolved: ReservationDateRepoObject = { ...resDate };

        withResolved.customer = await resDate.customer;

        return withResolved;
    })
);

console.log(reservationDatesWithResolvedRelationships[0].car);  // => Car { id: string, owner... }

// send off the JSON-like object here
Run Code Online (Sandbox Code Playgroud)

我觉得应该有一种方法来进行连接并强制进行急切加载,但是查询构建器或repository.find方法似乎都没有按照我设置的方式来执行此操作。

我也尝试添加{ lazy: true }和添加{ eager: true }到实体中的关系,但没有任何改变。

编辑:

仍然没有多少运气,但是我能够一起破解一个伪解决方案。

private parseRaw = name => raw => {
    const parsed = new ReservationDate();
    Object.entries(raw).forEach(([typeKey, value]) => {
        const [type, key] = typeKey.split('_');
        if (type === name) {
            parsed[key] = value;
        } else {
            parsed[type] = parsed[type] || {};
            parsed[type][key] = value;
        }
    });
    return parsed;
};

let reservationDates: ReservationDate[] = (await this.reservationDateRepository
    .createQueryBuilder('reservationDate')
    .leftJoinAndSelect('reservationDate.customer', 'customer')
    .limit(5)
    .getRawMany()).map(this.parseRaw('reservationDate'));
Run Code Online (Sandbox Code Playgroud)

超级丑陋的 hack,但它将原始的snake_casedb 结果转换为camelCase我需要发送的json 对象...

小智 -1

find()为了实现急切加载,您需要使用,

仅当您使用 find* 方法时,渴望关系才有效。如果您使用 QueryBuilder,急切关系将被禁用,并且必须使用 leftJoinAndSelect 来加载关系。Eager 关系只能在关系的一侧使用,不允许在关系的两侧使用 eager: true 。

文档在这里