TypeORM - Entity Manager vs Query Builder (feat: nullable, relations)

오픈소스·2023년 6월 21일
0

Entity Code

@Entity()
export class User {
    @PrimaryGeneratedColumn()
    id: number

    @Column()
    name: string

    @OneToMany(() => Photo, (photo) => photo.user)
    photos: Relation<Photo>[]
}

import { Column, Entity, ManyToOne, PrimaryGeneratedColumn, Relation } from 'typeorm';
import { User } from './User.js';

@Entity()
export class Photo {
  @PrimaryGeneratedColumn()
  id: number

  @Column()
  url: string

  @Column({ nullable: true })
  place?: string

  @ManyToOne(() => User)
  user: Relation<User> // https://stackoverflow.com/a/71983552
}

Entity Manager

    const photo = await AppDataSource.manager.findOne(Photo, {
        where: {
            id: 1,
            place: undefined
        },
        relations: {
            user: true
        }
    });
query: SELECT "Photo"."id" AS "Photo_id", "Photo"."url" AS "Photo_url", "Photo"."place" AS "Photo_place", "Photo"."userId" AS "Photo_userId", "Photo__Photo_user"."id" AS "Photo__Photo_user_id", "Photo__Photo_user"."name" AS "Photo__Photo_user_name" FROM "photo" "Photo" LEFT JOIN "user" "Photo__Photo_user" ON "Photo__Photo_user"."id"="Photo"."userId" WHERE ( ("Photo"."id" = $1) ) AND ( "Photo"."id" IN (1) ) -- PARAMETERS: [1]

Repository

    const photo = await AppDataSource.getRepository(Photo).findOne({
        where: {
            id: 1,
            place: "seoul"
        },
        relations: {
            user: true
        }
    });
query: SELECT "Photo"."id" AS "Photo_id", "Photo"."url" AS "Photo_url", "Photo"."place" AS "Photo_place", "Photo"."userId" AS "Photo_userId", "Photo__Photo_user"."id" AS "Photo__Photo_user_id", "Photo__Photo_user"."name" AS "Photo__Photo_user_name" FROM "photo" "Photo" LEFT JOIN "user" "Photo__Photo_user" ON "Photo__Photo_user"."id"="Photo"."userId" WHERE ( ("Photo"."id" = $1 AND "Photo"."place" = $2) ) AND ( "Photo"."id" IN (1) ) -- PARAMETERS: [1,"seoul"]

Query Builder

    const photoId = 1;
    const place = "seoul";

    const photo = await AppDataSource
        .getRepository(Photo)
        .createQueryBuilder('photo')
        .leftJoinAndSelect("photo.user", "user")
        .where(`photo.id=:photoId ${place ? 'AND photo.place=:place' : ''}`, {
            photoId,
            place,
        })
        .getOne();
query: SELECT "photo"."id" AS "photo_id", "photo"."url" AS "photo_url", "photo"."place" AS "photo_place", "photo"."userId" AS "photo_userId", "user"."id" AS "user_id", "user"."name" AS "user_name" FROM "photo" "photo" LEFT JOIN "user" "user" ON "user"."id"="photo"."userId" WHERE "photo"."id"=$1 AND "photo"."place"=$2 -- PARAMETERS: [1,"seoul"]

Result

{
    "id": 1,
    "url": "me.jpg",
    "place": "seoul",
    "user": {
        "id": 1,
        "name": "Timber"
    }
}

Eager and Lazy Relations

https://typeorm.io/many-to-one-one-to-many-relations

With eager loading enabled on a relation, you don't have to specify relations in the find command as it will ALWAYS be loaded automatically. If you use QueryBuilder eager relations are disabled, you have to use leftJoinAndSelect to load the relation.

https://typeorm.io/eager-and-lazy-relations

Eager relations only work when you use find* methods. If you use QueryBuilder eager relations are disabled and have to use leftJoinAndSelect to load the relation. Eager relations can only be used on one side of the relationship, using eager: true on both sides of relationship is disallowed.