본문 바로가기
프로그래밍/TypeORM

[TypeORM] One-to-one relations

by YuminK 2023. 9. 3.

https://orkhan.gitbook.io/typeorm/docs/one-to-one-relations

 

OneToOne 관계는 A가 오직 하나의 B 인스턴스를 가진다.

그리고 B는 오직 하나의 A 인스턴스를 가진다. 

다음 예시는 User와 Profile의 관계이다.

User는 하나의 Profile을 가지고 하나의 Profile은 하나의 User를 가진다.

 

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

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

    @Column()
    gender: string

    @Column()
    photo: string
}

 

import {
    Entity,
    PrimaryGeneratedColumn,
    Column,
    OneToOne,
    JoinColumn,
} from "typeorm"
import { Profile } from "./Profile"

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

    @Column()
    name: string

    @OneToOne(() => Profile)
    @JoinColumn()
    profile: Profile
}

 

여기 @OneToOne을 유저에게 줬고 Profile을 타겟으로 지정했다.

또한 @JoinColumn을 추가했는데 이는 관계에 한 쪽에만 추가되어야 하며 필수값이다.

@JoinColumn으로 설정하는 쪽이 외래키를 가지게 된다.

 

생성되는 테이블)

+-------------+--------------+----------------------------+
|                        profile                                      |
+-------------+--------------+----------------------------+
| id              | int(11)      | PRIMARY KEY AUTO_INCREMENT |
| gender      | varchar(255) |                            |
| photo        | varchar(255) |                            |
+-------------+--------------+----------------------------+

+-------------+--------------+----------------------------+
|                          user                                      |
+-------------+--------------+----------------------------+
| id              | int(11)      | PRIMARY KEY AUTO_INCREMENT |
| name        | varchar(255) |                            |
| profileId    | int(11)      | FOREIGN KEY        |
+-------------+--------------+----------------------------+

 

다시한번, @JoinColumn은 관계의 한 쪽 면에만 처리되어야 한다.

그리고 그 테이블은 데이터베이스 상에서 외래키를 가진다.

 

저장예시) 

const profile = new Profile()
profile.gender = "male"
profile.photo = "me.jpg"
await dataSource.manager.save(profile)

const user = new User()
user.name = "Joe Smith"
user.profile = profile
await dataSource.manager.save(user)

 

캐스케이드 옵션을 사용하는 경우, 한번에 처리할 수 있다.

 

User를 Profile과 함께 불러오기 위해서는 FindOptions의 relation을 사용하거나 QueryBuilder를 써야 한다.

const users = await dataSource.getRepository(User).find({
    relations: {
        profile: true,
    },
})

 

const users = await dataSource
    .getRepository(User)
    .createQueryBuilder("user")
    .leftJoinAndSelect("user.profile", "profile")
    .getMany()

 

eager 옵션을 사용하는 경우, 굳이 relation을 사용하지 않아도 알아서 로드를 해준다. 하지만 QueryBuilder 사용시에는 eager 옵션이 처리되지 않아 leftJoinAndSelect를 처리해야 한다. 

 

위 예시를 양방향으로 바꾸면 이렇다. 

import { Entity, PrimaryGeneratedColumn, Column, OneToOne } from "typeorm"
import { User } from "./User"

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

    @Column()
    gender: string

    @Column()
    photo: string

    @OneToOne(() => User, (user) => user.profile) // specify inverse side as a second parameter
    user: User
}

 

import {
    Entity,
    PrimaryGeneratedColumn,
    Column,
    OneToOne,
    JoinColumn,
} from "typeorm"
import { Profile } from "./Profile"

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

    @Column()
    name: string

    @OneToOne(() => Profile, (profile) => profile.user) // specify inverse side as a second parameter
    @JoinColumn()
    profile: Profile
}

 

@JoinColumn이 한쪽에 매핑된 것에 주의해라. 외래키를 가지는 쪽.

양방향 매핑은 다른 방향에서 QueryBuilder를 통한 데이터를 가져오는 것을 허용한다. 

const profiles = await dataSource
    .getRepository(Profile)
    .createQueryBuilder("profile")
    .leftJoinAndSelect("profile.user", "user")
    .getMany()

'프로그래밍 > TypeORM' 카테고리의 다른 글

[TypeORM] Relations  (0) 2023.09.04
[TypeORM] Many-to-one / one-to-many relations  (0) 2023.09.04
[TypeORM] Find Options - Advanced options  (0) 2023.09.02
[TypeORM] Find Options - Basic Options  (0) 2023.09.02
[TypeORM] EntityManager API  (0) 2023.09.02

댓글