// product.entity.ts
// typeorm
import { Column, Entity, 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) // 1 : 1
productSaleslocation: ProductSaleslocation;
}
@Entity
: class가 실행될 때, typeorm에 의해 Entity 테이블을 만들어줌@PrimaryGeneratedColumn(' ')
: 자동으로 생성될 값의 컬럼
increment
: 숫자로 데이터가 쌓일때마다 숫자가 하나 하나씩 올라가는 PK 키를 만들 수 있음uuid
( = Universal Unique IDentifier ) : 중복되지 않는 고유한 PK 키@Column({ type : ‘text’ })
: ERD에서 타입을 지정해주었는데, 엔티티에서 타입을 원하는대로 지정해 줄 수 있음. 정해주지 않으면( 빈 괄호로 둘 경우) default 값- boolean 타입을 만들때는 컬럼명 앞에 is 를 붙여줘서 이름만 보고도 boolean 타입인 것을 알 수 있게 해줌
@OneToOne()
: 두 테이블의 관계를 나타내는 것으로 @OneToOne( ) 은 한쪽에만 쓰거나, 양쪽에 모두 써줄 수 있음@JoinColumn()
: 두 테이블을 하나로 합쳐서 데이터를 가져와야하기에 사용하였으며, 한쪽 테이블에만 적어줘야함- productSaleslocation 의 타입은 ProductSaleslocation class 자체이기에 import 를 해왔습니다.
// product.entity.ts
@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() 생락갸능
@ManyToOne(() => ProductCategory) // N : 1 관계
productCategory: ProductCategory;
}
@ManyToOne()
: N : 1 관계를 나타내는 데코레이터@JoinColumn()
: Many 부분에 해당하는 테이블(product)에서는 JoinColumn( ) 이 생략 가능
- @ManyToOne( ) : @JoinColumn( ) 생략가능
- @OneToOne( ) : @JoinColumn( ) 반드시 필요
중간테이블 존재 => 따로 만들어주는 것이 아니라 연결을 해줄 때 자동으로 생성되는 테이블
// prodcutTag.entity.ts
import { Product } from 'src/apis/products/entities/product.entity';
import { Column, Entity, ManyToMany, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class ProductTag {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
// 연결되는 두 테이블 모두 필요함
@ManyToMany(() => Product, (products) => products.productTags)
// products는 productTags에 있는 products로 연결된다는 의미
products: Product[];
}
@ManyToMany()
: N :M의 관계를 가질 때는 두 테이블 모두 컬럼을 추가하여 연결해 주어야함(products) => products.productTags
: products 입장에서의 productTags 와의 관계를 명시해 준 것으로, N : M 관계에서는 두 테이블 모두 관계를 나타내 주어야함Product[]
: 하나의 태그에 상품이 여러개 해당될 수 있기에 배열로 나타내는 것
// product.entity.ts
@Entity()
export class Product {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
@Column()
description: string;
@Column()
price: number;
@Column()
isSoldout: boolean;
// soldedAt: Date
@JoinColumn()
@OneToOne(() => ProductSaleslocation)
productSaleslocation: ProductSaleslocation;
@ManyToOne(() => ProductCategory)
productCategory: ProductCategory;
@ManyToOne(() => User)
user: User;
@JoinTable() // 기준이 되는 한 쪽에만 작성
@ManyToMany(() => ProductTag, (productTags) => productTags.products)
productTags: ProductTag[];
}
@JoinTable()
: N : M 관계에서 생성되는 중간 테이블을 자동으로 만들어 주는 것으로 기준이 되는 테이블 한 쪽에만 작성(productTags) => productTags.products
: productTags 입장에서의 prodcuts 와의 관계를 명시해 준 것으로, N : M 관계에서는 두 테이블 모두 관계를 나타내 주어야함ProductTag[]
: 하나의 상품이 여러개의 태그에 해당 될 수 있기에 배열로 나타내는 것
// app.module.ts
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { GraphQLModule } from '@nestjs/graphql';
import { TypeOrmModule } from '@nestjs/typeorm';
import { BoardModule } from './apis/boards/board.module';
@Module({
imports: [
BoardModule,
ConfigModule.forRoot(),
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: 'src/commons/graphql/schema.gql',
}),
TypeOrmModule.forRoot({
type: process.env.DATABASE_TYPE as 'mysql',
host: process.env.DATABASE_HOST,
port: Number(process.env.DATABASE_PORT),
username: process.env.DATABASE_USERNAME,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE_DATABASE, // env파일 수정
entities: [__dirname + '/apis/**/*.entity.*'], // 수정
synchronize: true,
logging: true,
}),
],
})
export class AppModule {}
select name, SUM(price)
from product
group by name;
select name, MAX(price)
from product
group by name;
select name, price, isSoldout
from product
order by price asc;
select name, price, isSoldout
from product
order by price desc;
하나의 SQL 문에 포함되어 있는 또 다른 SQL 문을 의미
서브 쿼리를 포함한 쿼리문을 실행한다면, 서브 쿼리가 먼저 실행이 된 후 메인 쿼리가 실행
select name, price, isSoldout,
(select max(price) from product) as maxPrice
from product;
(select max(price) from product)
을 사용하여 상품 테이블에서 가격이 최대값인 상품을 조회하여 그 가격이름을as
를 통해 maxPrice로 바꿔서 상품 데이터를 조회한다는 의미