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

Posted

技术标签:

【中文标题】TypeORM postgresql 急切加载关系定义为惰性【英文标题】:TypeORM postgresql eager load relationships defined as lazy 【发布时间】:2019-02-19 08:15:21 【问题描述】:

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

我已将实体中的一些 OneToMany 和 ManyToOne 关系定义为惰性关系,当查询其中一个实体的数组时,我发现的最佳解决方案是大量的 promise 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[]>;

还有我的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>;

我需要检索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

我觉得应该有一种方法来进行连接并强制加载,但查询构建器或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'));

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

【问题讨论】:

【参考方案1】:

你需要使用find()来实现预加载,

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

Docs here

【讨论】:

以上是关于TypeORM postgresql 急切加载关系定义为惰性的主要内容,如果未能解决你的问题,请参考以下文章

急切加载时为 Eloquent 关系别名

Laravel 动态关系 - 在急切加载时访问模型属性

Laravel 5.4急切加载belongsToMany关系null绑定

如何为单个雄辩的对象急切加载关系?

Laravel 急切加载与添加子句的关系?

使用相同类型的多个关系改进急切加载