ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • typeorm - definition, entity
    개발 2022. 11. 29. 17:00

     

    ORM은 객체와 관계형 데이터베이스를 자동으로 매핑시켜주는 것을 말한다. 직접 Database Client를 켜고 테이블을 만들고 쿼리를 작성하는 방법도 있지만 ORM을 활용하면 번거로운 쿼리를 작성하지 않아도 되며 자동으로 데이터와 매핑까지 시켜줄 수 있기 때문에 여러모로 귀찮은 일을 한번에 해결할 수 있다. 

     

    typeorm은 타입스크립트, 자바스크립트에서 사용할 수 ORM이다. MySQL과 PostgreSQL을 포함해서 다양한 관계형 데이터베이스를 지원하고 스프링에서 사용되는 JPA와 거의 비슷한 수준의 기능을 제공하고 있다고 봐도 무방하다. 

     

    1. 초기화 

    import { DataSource } from 'typeorm';
    
    export const AppDataSource = new DataSource({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'common',
      password: 'common',
      database: 'common',
      synchronize: true,
      logging: true,
      entities: [],
    });

     

    다른 데이터베이스 초기화과정과 비슷하고 대신 type, entiries, synchronize 부분만 주목하자. type은 사용할 데이터베이스 종류다. 여기선 mysql 을 넣었는데 환경에따라서 postgres를 넣어도 된다. entities는 type-orm으로 매핑할 객체를 의미한다. 나중에 Entity 챕터에서 자세히 다뤄야겠다. synchronize는 코드상의 클래스를 실제 데이터와 자동으로 동기화 시켜줄 것인지를 설정하는 기능인데 반드시 조심해서 써야한다!!! 프로덕션에 true로 뒀다가 데이터 칼럼 타입 바뀌고 모든 데이터가 날라가는 경우가 종종 있으니 개발일 때는 true로 두고 프로덕션일때는 반드시 false로 두시길. 잘 모르겠다 하면 무조건 false를 추천한다!

     

    2. Entity 

     

    관계형 데이터베이스의 테이블과 매핑할 객체를 뜻한다. 객체 하나는 테이블 한개와 1:1로 매핑된다.  Question 이라는 클래스를 작성하고 Entity, Column 값을 설정해주면 데이터베이스에 동일하게 테이블이 생성된다. 

     

    @Entity()
    export class Question {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Column()
      title: string;
    
      @Column()
      text: string;
    }

     

    2.1 PrimaryGeneratedColumn()

     

    클래스의 key가 pk고 자동으로 생성되는 컬럼인 경우. synchronize 옵션을 true로 뒀을 경우 auto_increment 옵션이 자동으로 들어간다. 

     

    2.2 Column()

     

    테이블에 존재하는 칼럼과 매핑할 칼럼을 선택한다. 안에 옵션을 주지 않으면 테이블 칼럼 이름과 동일해야하는데 만약 다르게 가고 싶은 경우 (코드상에서는 카멜컨벤션을 따르고 싶은 경우) 에는 내부에 옵션을 준다. 

     

    export class User {
      @Column({name: "created_at"})
      createdAt: Date

     

    3. insert, save, update, delete 

     

    typeorm을 사용하면 복잡한 쿼리를 작성하지 않고도 간단하게 CRUD를 할 수 있다.  먼저 Blog라는 클래스를 Entity로 만들고 DataSource에 추가해두자. 

     

    import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
    
    @Entity()
    export class Blog {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Column()
      title: string;
    }
    import 'reflect-metadata';
    import { DataSource } from 'typeorm';
    import { Blog } from './entity/Book';
    
    const AppDataSource = new DataSource({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'common',
      password: 'common',
      database: 'common',
      synchronize: true,
      logging: true,
      entities: [Blog]
    });
    
    export default AppDataSource;

    3.1 CREATE 

    AppDataSource.initialize()
      .then(async () => {
        const blog = new Blog();
        blog.title = '아는개발자';
    
        AppDataSource.manager.save(blog);
      })

     

    DataSource를 초기화하고 위 코드처럼 객체를 생성한 후 save 명령어만 추가하면 바로 데이터에 저장된다. 

     

    3.2 READ

    const blog = await AppDataSource.manager.getRepository(Blog).findOne({
      where: {
        id: 1,
      },
    });
    
    console.log(blog);
    
    const blogs = await AppDataSource.manager.getRepository(Blog).find({
      take: 10,
    });
    
    console.log(blogs);

    이것도 동일하게 쿼리를 짜지 않고도 가능하다. findOne은 한개만 가져오는것, find는 여러개를 가져올 수 있다. findOne의 경우 한개만 가져올 수 있도록 where문이 필요하고 find에서 옵션을 넣지 않으면 모든 데이터를 가져오게 된다. 위 코드에서 넣은 take는 개수를 10개로 제한했다. 라이브러리에서 orderby 같은 옵션을 추가로 넣을 수 있다. 

     

    3.3 UPDATE

    const blog = await AppDataSource.manager.getRepository(Blog).findOne({
      where: {
        id: 1,
      },
    });
    
    blog.title = '아는개발자2';
    await AppDataSource.manager.save(blog);

    업뎃하는 작업은 객체 내부 property를 바꿔줌으로서 간단하게 처리가 가능하다. Create때와 마찬가지로 save 함수에 변경된 객체를 넣어주면 typeorm에서 이것을 업데이트로 인식하고 바꿔준다. 참 편한 기능이다. 

     

    3.4 DELETE

    await AppDataSource.manager.remove(blog);

    삭제는 manager 내부에 있는 remove라는 함수를 이용해서 처리할 수 있다. 

     

    그런데 실제로 운영을 하다보면 row를 삭제하지 않고 삭제 됐다고만 표시하고 데이터는 그대로 남아있게 하도록 한다. typeorm에서는 이런 경우를 위해 softRemove라는 것을 제공한다. softRemove는 실제 데이터를 삭제하지 않고 Delete 칼럼에 데이터가 삭제 됐다고 표시하는 기능이다. 

     

    import { Column, CreateDateColumn, DeleteDateColumn, Entity, PrimaryGeneratedColumn } from 'typeorm';
    
    @Entity()
    export class Blog {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Column()
      title: string;
    
      @DeleteDateColumn()
      deleted_at: Date;
    }

     

    softRemove를 사용하려면 @DeleteDateColumn 이라는 칼럼이 필요하다. 이렇게 추가된 칼럼은 데이터가 삭제 되는 시간을 표시하는 기능을 한다. 

     

    const blog = await AppDataSource.manager.getRepository(Blog).findOne({
      where: {
        id: 2,
      },
    });
    
    await AppDataSource.manager.softRemove(blog);

     

    실제로 데이터를 읽어와서 softRemove를 하면 DB 상에 deleted_at 값이 수정된 것을 확인할 수 있다.

     

     

    deleted_at 에 값이 세팅됐기 때문에 typeorm의 read로 찾아봐도 데이터는 없는 것으로 나온다. 

    '개발' 카테고리의 다른 글

    flutter - provider 패턴  (0) 2023.01.04
    typeorm - OneToOne, OneToMany, ManyToMany  (1) 2022.11.29
    flutter - BlocWidget  (0) 2022.10.06
    flutter - Bloc, Cubit, Stream  (0) 2022.10.06
    typescript interface/type  (0) 2022.09.07

    댓글

Designed by Tistory.