TypeORM & Entity

류연찬·2023년 5월 19일
0

GraphQL

목록 보기
12/17

1:1 테이블 생성

13-05-nestjs-with-graphql-docker-compose 폴더를 복사해 사본을 만들어주고 폴더명을 16-01-mysql-one-to-one 으로 변경해주세요.

TypeORM

board.entity.ts 파일을 보면, 우리는 게시판 클래스를 만들어놨습니다.

import { Field, Int, ObjectType } from '@nestjs/graphql';
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity() // typeorm한테 알려줌(mysql)
@ObjectType() // gql한테 알려줌
export class Board {
  @PrimaryGeneratedColumn('increment')
  @Field(() => Int)
  number: number;

  @Field(() => String)
  @Column()
  writer: string;

  @Field(() => String)
  @Column()
  title: string;

  @Field(() => String)
  @Column()
  contents: string;
}

이번에는 상품과 상품 위치에 대한 entity도 만들고, 서로 연결시켜보겠습니다.

GraphQL은 하지않고, typeorm만 해주겠습니다.

apis 폴더에 product 폴더와 productSalesloation 폴더를 새로 만들고, 각 폴더에 새 폴더 entities 를 만들고, 그 안에 새로운 파일 product.entity.tsproductSaleslocation.entity.ts 파일을 만들어줍니다.

productSaleslocation.entity.ts 파일 안에 ProductSaleslocation 클래스를 만들어줍니다.

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

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

  @Column()
  address: string;

  @Column()
  lat: number;

  @Column()
  lng: number;

  @Column({ type: 'timestamp' })
  meetingTime: Date;
}

product.entity.ts 파일 안에 Product 클래스를 만들고, ProductSaleslocationJoinColumnOneToOne 으로 연결해줍니다.

import { ProductSaleslocation } from 'src/apis/productSaleslocation/entities/productSaleslocation.entity';
import {
  Column,
  Entity,
  JoinColumn,
  OneToOne,
  PrimaryGeneratedColumn,
} from 'typeorm';

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

  @Column()
  name: string;

  @Column()
  description: string;

  @Column()
  price: number;

  @Column()
  isSoldout: boolean;

  @JoinColumn()
  @OneToOne(() => ProductSaleslocation)
  productSaleslocation: ProductSaleslocation;
}

@JoinColumn() 은 한쪽 테이블에만 적어야합니다.

@OneToOne() 은 한쪽에만 쓰거나, 양쪽에 써줄 수 있습니다.

여기서는 Product 에만 써주겠습니다.

app.module.ts 파일에 방금 만든 클래스를 entities 에 추가해줘야합니다.

기존의 방식대로 배열에 직접 하나씩 넣어줄 수도 있지만( entities: [Board] ), 양이 많이질수록 효율적이지 않습니다.

따라서, apis 폴더 밑에 있는 entity 파일은 다 적용되도록 다음과 같이바꿔줍니다.

entities: [__dirname + '/apis/**/*.entity.*']

현재 파일이 있는 절대경로에서 apis 폴더 안에 끝까지 들어가서, 파일명 중간에 .entity. 이 들어간 파일들을 선택한다는 뜻입니다.

// app.module.ts

import { Module } from '@nestjs/common';
import { ApolloDriverConfig, ApolloDriver } from '@nestjs/apollo';
import { GraphQLModule } from '@nestjs/graphql';
import { BoardModule } from './apis/board/board.module';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    BoardModule,
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: 'src/commons/graphql/schema.gql',
    }),
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'database',
      port: 3306,
      username: 'root',
      password: 'root', 
      database: 'myproject', // 변경
      entities: [__dirname + '/apis/**/*.entity.*'], // 변경
      synchronize: true,
      logging: true, 
    }),
  ],
})
export class AppModule {}

Docker 설정

docker.compose.yaml 파일에서 databaseenvironmentMYSQL_DATABASE: 'myproject' 를 추가해주세요.

version: '3.3'

services:
  backend:
    build:
      context: .
      dockerfile: dockerfile
    volumes:
      - ./src:/backend/src
    ports:
      - 3000:3000

  database:
    platform: linux/x86_64
    image: mysql:latest
    environment:
      MYSQL_DATABASE: 'myproject'
      MYSQL_ROOT_PASSWORD: 'root'
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
      - --skip-character-set-client-handshake
    cap_add:
      - SYS_NICE
    ports:
      - 3306:3306

이제 도커를 띄워보겠습니다.

터미널에서 해당 폴더로 이동해 docker compose builddocker compose up 을 해주세요.

그리고 테이블이 잘 만들어졌는지 DBeaver로 확인하겠습니다.

entity들이 잘 만들어져 있습니다.

💡 변화가 없어요..!!
database 우클릭 -> connection view -> Advanced 클릭 -> 다시 재연결 팝업창에서 '예' 클릭


1:N 테이블 생성

16-01-mysql-one-to-one 폴더를 복사해서 사본을 만든 후 폴더명을 16-02-mysql-many-to-one 으로 변경해주세요.

이번에는 ProductCategory 폴더를 만들고 안에 entities 폴더를 만들어 안에 새 파일을 만들어주세요.

productCategory.entity.ts 파일을 만들고 ProductCategory 클래스를 작성해줍니다.

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

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

  @Column()
  name: string;
}

마찬가지로, user 폴더를 만들고 안에 entities 폴더를 만들어 새파일을 만들어주세요.

user.entity.ts 파일을 만들고 User 클래스를 만듭니다.

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

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

  @Column()
  email: string;

  @Column()
  password: string;
}

이렇게 만들어준 userproductCategoryProductManyToMany 로 연결하겠습니다.

product.entities.ts 파일에 추가해보겠습니다.

import { ProductCategory } from 'src/apis/productCategory/entities/productCategory.entity';
import { ProductSaleslocation } from 'src/apis/productSaleslocation/entities/productSaleslocation.entity';
import { User } from 'src/apis/user/entities/user.entity';
import {
  Column,
  Entity,
  JoinColumn,
  ManyToOne,
  OneToOne,
  PrimaryGeneratedColumn,
} from 'typeorm';

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

  @Column()
  name: string;

  @Column()
  description: string;

  @Column()
  price: number;

  @Column()
  isSoldout: boolean;

  @JoinColumn()
  @OneToOne(() => ProductSaleslocation)
  productSaleslocation: ProductSaleslocation;

  // user 연결
  @ManyToOne(() => User)
  user: User;

  // productCategory 연결
  @ManyToOne(() => ProductCategory)
  productCategory: ProductCategory;
}

컨테이너를 띄워보겠습니다.

터미널에서 해동 폴더로 이동해 docker compose builddocker compose up 명령어로 실행하겠습니다.

그리고 DBeaver를 통해 확인해보겠습니다.



N:M 테이블 생성

16-02-mysql-many-to-one 폴더를 복사하여 사본을 만들고 폴더명을 16-03-mysql-many-to-many 로 변경해주세요.

apis 폴더 안에 productTag 폴더를 생성하고 entities 폴더 안에 productTag.entity.ts 파일을 생성해주세요.

import { Product } from 'src/apis/product/entities/product.entity';
import { Column, Entity, ManyToMany, PrimaryGeneratedColumn } from 'typeorm';

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

  @Column()
  name: string;

  @ManyToMany(() => Product, (product) => product.productTags)
  products: Product[];
}

products 컬럼을 ManyToMany 로 연결해주겠습니다.

import { ProductCategory } from 'src/apis/productCategory/entities/productCategory.entity';
import { ProductSaleslocation } from 'src/apis/productSaleslocation/entities/productSaleslocation.entity';
import { ProductTag } from 'src/apis/productTag/entities/productTag.entity';
import { User } from 'src/apis/user/entities/user.entity';
import {
  Column,
  Entity,
  JoinColumn,
  JoinTable,
  ManyToMany,
  ManyToOne,
  OneToOne,
  PrimaryGeneratedColumn,
} from 'typeorm';

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

  @Column()
  name: string;

  @Column()
  description: string;

  @Column()
  price: number;

  @Column()
  isSoldout: boolean;

  @JoinColumn()
  @OneToOne(() => ProductSaleslocation)
  productSaleslocation: ProductSaleslocation;

  @ManyToOne(() => User)
  user: User;

  @ManyToOne(() => ProductCategory)
  productCategory: ProductCategory;

  // productTag 연결
  @JoinTable()
  @ManyToMany(() => ProductTag, (productTag) => productTag.products)
  productTags: ProductTag[];
}

ManyToMany 는 둘 중 하나에 JoinTable() 을 걸어줘야하기 때문에 Product 클래스에서 해주겠습니다.

컨테이너를 띄우고 DBeaver로 접속해 엔티티 관계도를 확인해보겠습니다.



SQL 쿼리 작성하기

이번에는 직접 SQL 쿼리문을 작성해보겠습니다.

16-03 의 컨테이너는 계속 작동시켜주세요.

MySQL in Docker

도커를 통해 직접 컨테이너 안으로 들어가, mysql에 접속해보겠습니다.

다른 터미널을 열어 16-03 폴더로 위치 후, docker ps 로 mysql이 실행되고 있는 컨테이너의 아이디를 복사합니다.

docker exec -it 컨테이너ID /bin/bash 명령어를 입력해 컨테이너 안으로 들어갑니다.

mysql -u root -p 를 입력하고 비밀번호 root 를 입력해줍니다.

show databases; 를 적고 엔터를 치면 데이터베이스 목록이 나옵니다.

use myproject; 를 하면 myproject 데이터베이스를 선택하여 이후 명령어를 수행하게 됩니다.

이후 show tables; 명령어를 입력하면 해당 데이터베이스가 가지고 있는 테이블의 목록을 보여줍니다.

이 중에서 product 테이블이 어떻게 구성되어 있나 보겠습니다.

desc product; 명령어를 통해 알 수 있습니다.



Script in DBeaver

방금은 도커 컨테이너 안으로 직접 들어가 명령어를 직접 입력했습니다.

이번에는 DBeaver를 이용해서 SQL문을 작성해보겠습니다.

DBeaver에서 도커 컨테이너로 띄운 mysql 서버에 접속한 후 SQL 버튼을 누르면 스크립트 작성할 수 있는 창이 뜨게 됩니다.

열린 스크립트 창에 아래와 같이 SQL문을 적어줍니다.

show databases;
use myproject;
show tables;
desc product;

실행하는 방법은 실행하고자 하는 명령어를 한줄 드래그하고 Ctrl + Enter 를 누르면 됩니다.

각각 한줄씩 실행했을 때, 아래와 같은 결과물을 볼 수 있습니다.



이번에는 users 테이블에 SQL 문으로 데이터를 직접 넣어보겠습니다.

스크립트 창에 아래와 같이 적고 Ctrl + Enter 를 눌러 실행해주세요.

잘 들어갔는지 유저 테이블에 들어가서 새로고침하고 확인해보겠습니다.

정상적으로 들어가져 있습니다.

이번에는 쿼리문으로 조회해보겠습니다.

SELECT * FROM user;
SELECT email from user;

잘 들어가져 있네요.

상품도 추가해보겠습니다.

INSERT INTO product(id, name, description, price, isSoldout) values(uuid(), '마우스', '좋은 마우스', 1000, false);

이제 한번 조회해보겠습니다.

SELECT * FROM product;



유저와 상품에 한개씩 데이터를 넣어봤습니다.

이 두개를 연결해보겠습니다.

데이터를 업데이트해서 상품에 유저를 연결하겠습니다.

아까 생성된 유저의 아이디를 복사해주세요.

상품 데이터에 유저 아이디를 추가하도록 데이터를 업데이트할건데, 모든 상품이 바뀌면 안됩니다.

어떤 상품을 업데이트하기 원하는지 조건을 where 에 적어줍니다.

UPDATE product SET userId = 'e10b80cc-f664-11ed-a9b3-0242ac160002' WHERE name = '마우스';

상품 데이터에 유저 아이디를 넣어줬으니, 두개의 테이블을 합쳐서 한번에 조회해보겠습니다.

SELECT * FROM product, user;

정상적으로 작동했습니다.

0개의 댓글