ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • typeorm - OneToOne, OneToMany, ManyToMany
    개발 2022. 11. 29. 20:00

     

    typeorm을 사용하면 객체들간의 관계도 데이터베이스상에 매핑이 가능하다. 1:1, 1:N, M:N 처럼 데이터베이스 수업시간에 배웠던 껄끄러운 관계들을 typeorm을 이용해서 일목요연하게 정리해보자. 

     

    1. OneToOne

     

    객체와 다른 객체간의 관계가 1:1인 경우다. 객체 A, B가 있다면 A 객체가 B 한개를 소유하고 B 객체는 A에만 속하는 관계가 이렇다. 

     

    @Entity()
    export class User {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Column()
      name: string;
    
      @OneToOne(() => Profile)
      @JoinColumn()
      profile: Profile;
    }
    
    
    @Entity()
    export class Profile {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Column()
      gender: String;
    
      @Column()
      photo: String;
    }

     

    User는 Profile 객체와 1:1로 매핑한다. 이때 @JoinColumn 이라는 어노테이션이 붙었는데 이 어노테이션이 붙은 테이블에서 외래키를 붙인다. 위 코드의 객체로 생성된 User 테이블은 다음과 같다. 

     

    user table
    +------------+--------------+------+-----+---------+----------------+
    | Field      | Type         | Null | Key | Default | Extra          |
    +------------+--------------+------+-----+---------+----------------+
    | id         | int          | NO   | PRI | NULL    | auto_increment |
    | name       | varchar(255) | NO   |     | NULL    |                |
    | profileId  | int          | YES  | UNI | NULL    |                |
    +------------+--------------+------+-----+---------+----------------+
    
    profile table
    +------------+--------------+------+-----+---------+----------------+
    | Field      | Type         | Null | Key | Default | Extra          |
    +------------+--------------+------+-----+---------+----------------+
    | id         | int          | NO   | PRI | NULL    | auto_increment |
    | gender     | varchar(255) | NO   |     | NULL    |                |
    | photo      | varchar(255) | NO   |     | NULL    |                |
    +------------+--------------+------+-----+---------+----------------+

     

    User 테이블에 profileId라는 외래키가 붙은 것을 확인할 수 있다. typeorm에서 테이블상에서 user 테이블에 profileId를 붙여서 관계를 표현했다.

     

    1.1 관계 생성

     

    async function createOneToOneExamples(manager: EntityManager) {
      const profile = new Profile();
      profile.gender = 'male';
      profile.photo = 'me.jpg';
    
      await manager.save(profile);
    
      const user = new User();
      user.name = 'Joe Smith';
      user.profile = profile;
    
      await manager.save(user);
    }

     

    typeorm의 일반 생성 작업처럼 객체 내부 property를 변경하면 관계도 생성된다. User의 profileId 칼럼에 방금 매핑한 profile id값이 추가된다. 

     

    2. OneToMany

     

    하나의 객체가 여러개의 객체를 소유하는 것을 말한다. A라는 객체가 B1, B2, B3라는 객체를 동시에 소유하는데 B1, B2, B3는 A에만 속하는 관계를 뜻한다. 하나의 유저가 여러개의 사진을 소유하는 관계는 아래 코드로 표현 가능하다. 

     

    @Entity()
    export class User {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Column()
      name: string;
    
      @OneToMany(() => Photo, (photo) => photo.user)
      photos: Photo[];
    }
    
    @Entity()
    export class Photo {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Column()
      url: string;
    
      @ManyToOne(() => User, (user) => user.photos)
      user: User;
    }

     

    Photo 테이블에서는 소속된 유저의 id가 칼럼으로 추가된다. 

     

    mysql> show columns from photo;
    +------------+--------------+------+-----+---------+----------------+
    | Field      | Type         | Null | Key | Default | Extra          |
    +------------+--------------+------+-----+---------+----------------+
    | id         | int          | NO   | PRI | NULL    | auto_increment |
    | url        | varchar(255) | NO   |     | NULL    |                |
    | userId     | int          | YES  | MUL | NULL    |                |
    +------------+--------------+------+-----+---------+----------------+

     

     

    2.1 생성 작업

      const photo1 = new Photo();
      photo1.url = 'me.jpg';
      await manager.save(photo1);
    
      const photo2 = new Photo();
      photo2.url = 'me-and-bears.jpg';
      await manager.save(photo2);
    
      const user = new User();
      user.name = 'John';
      user.photos = [photo1, photo2];
    
      await manager.save(user);

    User 객체의 photos property에 photo1, photo2를 넣고 save만 하면 바로 업데된다. 

     

    3. ManyToMany

     

    객체가 여러객체를 소유할 수 있고 상대 객체도 여러 객체를 소유할 수 있는 형태다. A가 B1, B2, B3를 소유한다면 B1도 A1, A2, A3를 소유하는 관계다. 예로 질문은 여러개의 카테고리를 가질 수 있고 마찬지로 여러개의 카테고리는 하나의 질문을 갖는 형태가 이렇다. 

     

    @Entity()
    export class Question {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Column()
      title: string;
    
      @ManyToMany(() => Category, {})
      @JoinTable() // 반드시 필요하다. 관계를 소유하는 쪽에다가 붙인다.
      categories: Category[];
    }
    
    @Entity()
    export class Category {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Column()
      name: string;
    }

     

    ManyToMany 관계에선 두 객체간의 관계를 표현할 테이블이 생성된다. 

     

    +------------+------+------+-----+---------+-------+
    | Field      | Type | Null | Key | Default | Extra |
    +------------+------+------+-----+---------+-------+
    | questionId | int  | NO   | PRI | NULL    |       |
    | categoryId | int  | NO   | PRI | NULL    |       |
    +------------+------+------+-----+---------+-------+

     

    3.1 객체 생성

     

      const category1 = new Category();
      category1.name = 'animals';
      await manager.save(category1);
    
      const category2 = new Category();
      category2.name = 'zoo';
      await manager.save(category2);
    
      const question = new Question();
      question.title = 'dogs';
      question.text = 'who let the dogs out?';
      question.categories = [category1, category2];
      await manager.save(question);

    이것도 동일하게 categories라는 property 값에 추가하면 가능하다. 현재는 Question이 Category를 소유하는 형태로 코드가 짜여져 있는데 그 역의 관계, Category가 Question을 소유하게 하는 관계도 가능하다. 

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

    dart - mixin  (0) 2023.01.04
    flutter - provider 패턴  (0) 2023.01.04
    typeorm - definition, entity  (0) 2022.11.29
    flutter - BlocWidget  (0) 2022.10.06
    flutter - Bloc, Cubit, Stream  (0) 2022.10.06

    댓글

Designed by Tistory.