위 사진 처럼, 하나의 post는 meta_option 하나를 가지고있다. 하지만 meta_option은 post를 가지고있지 않으므로 post와 meta_option은 단방향성 1 to 1 관계를 가지고있다고 볼 수 있다.
단방향 관계 ➡
두 엔티티가 연관 관계를 맺고 있을 때, 한 쪽의 엔티티만 다른 쪽을 참조하고 있는 것을 의미합니다.
양방향 관계 ↔
두 엔티티가 연관 관계를 맺고 있을 때, 양 쪽이 서로를 참조하고 있는 것을 의미합니다.
post.entity.ts 파일
import {
Entity,
PrimaryGeneratedColumn,
Column,
OneToOne,
JoinColumn,
} from 'typeorm';
import { MetaOption } from 'src/meta-options/meta-option.entity';
@Entity()
export class Post {
...
@OneToOne(() => MetaOption)
@JoinColumn()
metaOptions?: MetaOption;
}
🐤단방향 관계를 만드는 방법🐤
단방향의 주체 엔티티 파일에서 단방향이 이루어질 프로퍼티에 밑 두 데코레이터를 추가하면된다
@OneToOne(()=> Entity)
=> 인자로 객체 엔티티를 넘겨줌
@JoinColumn()
=> 엔티티 테이블에 컬럼을 만든다. 단방향 일때만 쓰인다.
위의 경우 Post 테이블에 meta options ID 컬럼을 만든다.
결과:
위 엔티티 구조도에서 봤듯이, Post 테이블에서는 meta_option이 필요하다. 만약 사용자가 post를 업로드할시 meta_options도 같이 업로드한다면, 먼저 meta_options를 db에 생성해야한다.
즉, PostsService 파일에서 meta_options DB 저장 -> post DB 저장
사실 이 방법은 코드가 길어진다. typeORM에서 cascade라는 더 좋은 방법이 있는데 이 방법을 먼저 알아본뒤 밑에 적기로한다.
post를 생성할때 metaOptions DB와 post DB에 접근해야한다.
즉, postService.ts
에서 metaOptions와 post repository가 둘다 필요하므로 module
파일에서 둘의 엔티티를 imports 해야한다.
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Post } from '../post.entity';
import { Repository } from 'typeorm';
import { MetaOption } from 'src/meta-options/meta-option.entity';
import { CreatePostDto } from '../dtos/createPost.dto';
@Injectable()
export class PostsService {
constructor(
@InjectRepository(Post)
private readonly postsRepository: Repository<Post>,
@InjectRepository(MetaOption)
private readonly metaOptionsRepository: Repository<MetaOption>,
) {}
public async create(createPostDto: CreatePostDto) {
//Create metaOptions
let metaOptions = createPostDto.metaOptions
? this.metaOptionsRepository.create(createPostDto.metaOptions)
: null;
if (metaOptions) { //1. 먼저 metaOptions DB 저장
await this.metaOptionsRepository.save(metaOptions); //save 메소드를 이용해야지 DB에 저장됨
}
// Create post
let post = this.postsRepository.create(createPostDto);
// Add metaOptions to the post
if (metaOptions) { // 2. post 레포에 위 생성한 metaOptions 할당
post.metaOptions = metaOptions;
}
return await this.postsRepository.save(post); //3. post DB 저장
}
}
create 메소드에서는 await를 쓰지않아도된다.
오직 save 메소드에서만 await가 필요한데, 프로미스를 반환하기때문.
위에 코드는 PostsService에서 metaOptionsRepository과 postsRepository를 둘다 주입하고있는데 이러한 방법보다 훨씬 간편한 cascade를 알아보자
내가 원하는 작업?
post db 생성할때 meta_options도 db에 생성되는것.
import {
Entity,
...
OneToOne,
JoinColumn,
} from 'typeorm';
import { MetaOption } from 'src/meta-options/meta-option.entity';
@Entity()
export class Post {
...
@OneToOne(() => MetaOption, {
cascade: true,
})
@JoinColumn()
metaOptions?: MetaOption;
}
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Post } from '../post.entity';
import { Repository } from 'typeorm';
import { CreatePostDto } from '../dtos/createPost.dto';
@Injectable()
export class PostsService {
constructor(
@InjectRepository(Post)
private readonly postsRepository: Repository<Post>,
) {}
public async create(createPostDto: CreatePostDto) {
// Create post
let post = this.postsRepository.create(createPostDto);
return await this.postsRepository.save(post);
}
기존에는 create 함수 안에서 metaOptionRepository를 주입하고 create,post까지 했는데 cascade:true
를 설정하면 postsRepository에서 post만 create해도 metaOptions 까지 db에 저장된다.
post를 생성했는데 meta_option 테이블에도 잘 저장이 되었다.
eager / define relationship
eager= > 모든 테이블 다 가져와서 비효율적일수도
What we are going to work on in this particular video is a sequential deletion, where we will first
delete the post and then we will delete the meta option.
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Post } from '../post.entity';
import { Repository } from 'typeorm';
@Injectable()
export class PostsService {
constructor(
@InjectRepository(Post)
private readonly postsRepository: Repository<Post>,
) {}
public async findAll(userId: string) {
const posts = await this.postsRepository.find();
return posts;
}
}
post 테이블에있는 모든 데이터를 가져오고싶을때 postsRepository.find()
하면 된다. 하지만 리턴값을 보면 metaOptions
가 없다. metaOptions은 다른 테이블에서 가져온것이기때문에 안불러와지는것같다. 이런경우
public async findAll(userId: string) {
const posts = await this.postsRepository.find({
relations: {
metaOptions: true,
},
});
return posts;
}
find 메소드 안에 relations를 추가해서 원하는 프로퍼티를 작성한 뒤 true 해주면된다
잘가져온다.
또다른 방법으로 eager
라는 것이 있는데, 이는 모든 프로퍼티를 다 가져와서 남용한다면 성능에 문제가생길수도있다.
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Post } from '../post.entity';
import { Repository } from 'typeorm';
@Injectable()
export class PostsService {
constructor(
@InjectRepository(Post)
private readonly postsRepository: Repository<Post>,
) {}
public async findAll(userId: string) {
const posts = await this.postsRepository.find();
return posts;
}
}
------------------------------------------------------------
post.entity.ts
@Entity()
export class Post {
...
@OneToOne(() => MetaOption, {
cascade: true,
eager: true,
})
@JoinColumn()
metaOptions?: MetaOption;
}
참조: https://velog.io/@dnjscksdn98/JPA-Hibernate-Bidirectional-Unidirectional-Relationships