Skip to content

typeorm_server

JunBae edited this page Nov 28, 2019 · 7 revisions

typeorm

설명

typeorm의 탐색

  • find - select와 같음
  • findOne - 결과 한개만
  • findAndCount - [결과, 갯수]형식으로 출력한다.

모델 정의하는법

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

@Entity()
export class 모델명 {
  @PrimaryGeneratedColumn({ 옵션 })
  컬럼이름: 타입;
  @column({ 옵션 })
  컬럼이름: 타입;
  ...
}
  • 컬럼 선언
    • @PrimaryGeneratedColumn()
      • PrimaryKey로 선정하고 Auto Increment도 같이 적용한다.
    • @column()
      • 하나의 컬럼을 만든다
  • 컬럼타입(mysql기준)
    • string - 기본 varchar(255)로 선언된다.
      • 옵션으로 {type:text}를 선언하게되면 text로 생성된다.
    • number - 기본 int(11)로 선언된다.
    • boolean - 기본 tiny(4)로 선언된다.
  • 컬럼 옵션
    • type
    • nullable
    • default
  • 관계 설정
    • 관계를 설정할때 이름을 설정할때 헷갈리지않게 신중히 작성해야 find가 잘 작동된다.
    • @OneToMany(관계설정)
      • 1대다 의 관계
      • 외래키가 만들어지지않지만 상대와 연결여부를 알 수있다고 한다.
    • @ManyToOne(관계설정)
      • 다대1 의 관계
      • 선언이 된 모델이 외래키를 가지게된다.
    //유저가 여러개의 상품을 가진다고 할때
    //users
    @OneToMany(
      type => Products,
      product => product.seller//이부분에 주목해야함. product를 기준으로 user를 어떻게 선언됐는지 정하는부분으로 find에서 relations에서 모델명을 이 이름으로 사용해야한다.
    )
    products: Products[];//실제 데이터베이스에서는 products_id라고 만들어진다.(products가 id를 pk로 가질경우)
    
    //products
    @ManyToOne(
      type => Users,
      user => user.products//user기준으로 products를 products라고 선언하고 있다는 표현
    )
    seller: Users;//users가 seller라고 표현

find 사용법

  • find 구조
  • find(모델명,{find옵션});
import { Auction_logs } from "../models/Auction_logs"

...

this.em.find(Auction_logs,{find옵션});
  • find 옵션들
    • relations - 연관된 테이블을 join해서 보여준다.
    find(models,{relations:["연결된모델명","또다른모델명",...]})
    // 위에서 선언한 users, products를 이용한 예시
    findAndCount(Products, {relations: ["seller"]}//users가 아닌 seller로 해야 연결이된다.
    • join - relations와 같다.
    find(models,{
         join: {
         alias: "user",
         leftJoinAndSelect: {
             profile: "user.profile",
             photo: "user.photos",
             video: "user.videos"
         }
     })
    • where
      • mysql의 where과 같은 기능으로, 조건에 맞는 데이터를 찾는다.
      • MoreThanOrEqual
        • =를 표현하는 함수이다.

    find(models,{where:{컬럼이름:원하는값}}
    find(models,{where:{컬럼이름:MoreThanOrEqual(원하는값)}}
    • order
    find(models,{order:{컬럼이름:"정렬기준"}
    find(models,{order:{컬럼이름:"DESC"}
    • skip, take
      • 페이징(skip은 시작위치, take는 가져오는 갯수)
      • ex) skip(0) take(10)은 1부터 10까지 가져온다.
    find(models,{skip:1,take:2}
    • cache
      • 캐쉬여부
    find(models,{cache:true}

raw query

  • 단순히 mysql로 된 쿼리를 날릴때 사용
   await this.em.query("select * from ~~~");

라우팅

  • controllers폴더를 참고
@JsonController("/log")// /log로 들어온다.
export class LogController {
  constructor(private readonly logService: LogService) {}//service를 사용하도록 초기화하는부분

  @Get()//메소드 지정
  public find() {//해당 메소드가 처리하는 함수
    return this.logService.find()//서비스 연결
  }

  @Get("/:id")//파라메터 지정
  public findOne(@Param("id") id: string) {//Get의 파라메터를 꺼내는 방식
    return this.logService.findOne(parseInt(id))
  }
}
  • 메소드
    • @Get(), @Post(), @Put(), @Delete()과 같이 사용가능
  • 파라메터 파싱
    • Get
    @Get("/:id")
    public findOne(@Param("id") id: string) {}//Param을 이용해 추출가능
    • Post
    @Post()
    public findOne(@BodyParam("userid") userid: number) {}//BodyParam을 이용해 추출가능

폴더구조

  • models

    • 데이터베이스 테이블을 정의하는곳
      • @PrimaryGeneratedColumn()
        • 키를 정의
        • generated라 선언하여 auto incresemenet도 같이 적용
      • @Column
        • 일반적인 컬럼을 선언
    • 속성
      • string, number, date, boolean등을 사용가능
    • 관계
      • OneToOne, OneToMany, ManyToOne, ManyToMany를 선언가능
    • 예시
      import { Entity, PrimaryGeneratedColumn, Column, OneToMany, ManyToOne} from 'typeorm';
      import { Images } from './Images';
      import { Users } from './Users2';
      
      @Entity()
      export class Products {
      @PrimaryGeneratedColumn()
      id: number;
      
      @Column()
      title: string;
      
      
      @OneToMany(type => Images, images => images.id)
      images: Images[];
      
      @ManyToOne(type => Users, users => users.id)
      user: Users;
      }
      
  • repositories

    • entity manager와 repository

      • entity manager를 통해 insert, update, create, delete(crud)가 가능
      • repository는 entitymanager와 비슷하지만, concrete entity로 제한된다.
    • repository는 하나의 테이블에서 나오는 로직을 처리

        import { EntityRepository, Repository, EntityManager } from 'typeorm';
        import { Users } from '../models/Users';
        /** Entity Manager - Constructor Injecction
        *  1. TypeOrm 역시 TypeDI의 Container를 사용한다.(server.ts 참조)
        *  2. 그래서 TypeOrm의 EntityManager는 TypeDI에 등록되있다.
        *  3. 그렇기 때문에, 아래서 @Inject 데코레이터 없이 생성자 주입이 가능하다.
        *  4. TODO: TypeDi와 Container 연결없이, 생성자 Injection이 되는지 확인해보자.
        */
    
        @EntityRepository()
        export class UserRepository {
        constructor(private readonly em: EntityManager) {}
    
        public find() {
            return this.em.find(Users);
        }
    
        public findOne(id: number) {
            return this.em.findOne(Users, id);
        }
    
        //find 심화
        //select * from auction_log where user_id=user_id, is_winning=true
        //위의 내용을 type orm으로 바꾸기
        public findBuyLogs(user_id : number) {
        return this.em.find(Auction_logs,{
            where:{
                user: { id: user_id },
                is_winning:true
            }
        });
    
    
        public save(user: Users) {
            return this.em.save(user);
        }
        }
    
    
  • services

    • 필요에 따라 여러 repository를 조합하여 처리 하기 위한 처리단계
        import { Service } from 'typedi';
        import { UserRepository } from '../repositories/UserRepository';
        import { InjectRepository } from 'typeorm-typedi-extensions';
        import { Users } from '../models/Users';
    
        /** TODO: Transaction을 어떻게 처리해야 좋을까? */
        @Service()
        export class UserService {
        constructor(
            @InjectRepository() private readonly userRepository: UserRepository
        ) {}
    
        /** GET */
        public find() {
            return this.userRepository.find();
        }
    
        public findOne(id: number) {
            return this.userRepository.findOne(id);
        }
    
        /** POST */
        public create(user: Users) {
            return this.userRepository.save(user);
        }
    
        /** PUT, PATCH */
        public update(id: number, user: Users) {
            /**TODO: 해당 id값으로 Entitiy를 조회해서, 새로운 user 엔티티로 변경 */
        }
    
        /** DELETE */
        public delete(id: number) {
            /**TODO: 해당 id값으로 Enitity 삭제 */
        }
        }
    
    
  • controllers

    • service에서 함수를 사용한다.

    • api폴더에 파일을 생성한다.

    • 예시

        import {
        JsonController,
        Get,
        Param,
        Post,
        Body,
        Patch,
        Put,
        Delete,
        OnUndefined
        } from 'routing-controllers';
    
        //service와 모델을 import한다.
    
        import { UserService } from '../../services/UserService';
        import { Users } from '../../models/Users';
    
        /** TypeDi Constructor Injection 작동 방식
        * 1. TypeDi의 Container를 routing-controllers가 사용한다.(server.ts 소스 코드 참조)
        * 2. TypeDi가 Controller로 등록된 클래스들을 알고 있다.
        * 3. TypeDi는 @Inject를 통해서 dependency를 주입하는데, 생성자 주입(Constructor Injection)의 경우 @Inject를 생략해도 된다.
        */
        //컨트롤러 설정 부분
        //아래의 의미는 localhost:3000/api/users 로 시작한다는 의미이다.//자신이 만든 api이름을 넣으면 된다.
        @JsonController('/users')
        export class UserController {
        constructor(private readonly userService: UserService) {}
    
        @Get()
        public find() {
            return this.userService.find();
        }
        //get으로 받는 부분
        //get의 api의 마지막은 param이 아닌경우 에러가 난다. 
        //ex) Get('/feafea/:num')(o) / Get('/feafea')(x) 
        //Get내부에서 조건문을 사용하는 방식을 고려해보자.
        @Get('/:id')
        public findOne(@Param('id') id: string) {
            return this.userService.findOne(parseInt(id));
        }
    
        @Post()
        public create(@Body() user: Users) {
            //TODO: user을 Users Model에 맞게 class-transformer를 사용해서 처리하자
            return this.userService.create(user);
        }
        //post으로 받는 부분
        //post body로 값을 넘기는 경우 BodyParam 을 이용하자
        // @BodyParam("name") userName: number
        //위의 의미는 body의 name부분을 받아서 userName에 넣는다는 의미이다. 헷갈리지 않도록 하자.
        @Post('/tests')
        public aaabbbb(@BodyParam("name") userName: number) {
            if(userName>10){//이런식으로 내부에 조건문을 활용할수 있다.//쓸지는 모르지만 참고//좋은 방식인지는 모르겠다.
            return [1,1,1];
            }
            return this.logService.findBuyLogs(userName);
        }
    
        @Put('/:id')
        @Patch('/:id')
        public update(@Param('id') id: string, @Body() user: Users) {
            //TODO: user을 Users Model에 맞게 class-transformer를 사용해서 처리하자
            return this.userService.update(parseInt(id), user);
        }
    
        @Delete('/:id')
        public delete(@Param('id') id: string) {
            return this.userService.delete(parseInt(id));
        }
        }
    
    
  • typeorm관련 https://typeorm.io

  • find-option https://github.com/typeorm/typeorm/blob/master/docs/find-options.md

  • typeorm 라우팅 https://github.com/typestack/routing-controllers

  • many-to-one 관계에서의 find를 하는법 https://github.com/typeorm/typeorm/issues/2552