Sequelize Foreign Key

국물빌런·2020년 9월 27일
1

foreign key란?

it용어를 풀어쓰기란 정말 쉽지가 않다.
수많은 도메인 지식과 배경지식이 필요한 단어를 이런 배경지식을 건너뛰고 설명한다는것이 가능하기나 할까..
외래키가 무엇인지 이해하려면 RDB에서 관계를 표현하는 방법에 대해 이해해야 한다.
외래키는 RDB에서 제공하는 제약조건중의 하나인데 이 제약조건을 어떻게 쓰냐가 아니라 왜 쓰는지가 더 중요하기 때문이다.
일단 RDB에서 관계 표현을 어떻게 하는지부터 알아보자
RDB는 기본적으로 테이블이라는 개념으로 데이터를 표현하는데 배달의 민족을 생각해보자. 매장이 있고 해당 매장에는 유저 리뷰가 달린다.
RDB에 매장과 리뷰, 유저를 표현하면 대략 아래와 같다.

create table M_STORE
(
    id            int auto_increment primary key,
    store_cd   	  varchar(5)    null,
    stor_nm       varchar(255) null,
);

create table M_REVIEW
(
    id         int auto_increment primary key,
    user_id    varchar(255)  null,
    context    varchar(1024) null,
    store_cd   varchar(5)    null
);

create table M_USER
(
    id         int auto_increment primary key,
    email      varchar(255) null,
    constraint email unique (email)
);

하나의 매장은 여러개의 리뷰를 가질수 있고
유저는 매장에 대해 여러개의 리뷰를 쓸 수 있다.

ALTER TABLE M_REVIEW ADD CONSTRAINT fk_review1 FOREIGN KEY (STORE_CD) REFERENCES M_STORE (STORE_CD);

sql은 상당히 직관적인 문법을 제공한다.
그대로 해석하면 된다
M_REVIEW을 변경한다, 제약조건을 fk_review1이라는 이름으로 추가한다,
제약 조건은 foreign key이며 store_cd컬럼이다,
m_store의 store_cd를 참고한다
뭐 대충 이런식이다.
나머지도 해보자
유저는 여러개의 리뷰를 쓸수 있고 리뷰는 한명의 유저를 가진다
foreign key는 1:n관계에서 n에다가 걸어준다

ALTER TABLE M_REVIEW ADD CONSTRAINT fk_review2 FOREIGN KEY (user_id) REFERENCES M_USER (email);

이제 m_review컬럼의 store_cd컬럼은 m_store에 store_cd에 있는 값만 넣을수 있는 제약조건이 생겼다
m_review컬럼의 user_id컬럼은 m_user에 email에 잇는 값만 들어갈 수 있는 제약조건이 생겼다.

이것이 RDB에서 foreign key이다.
본론으로 넘어가서 Sequelize에서는 이 관계를 어떻게 표현하는지 알아보자
sequelize는 관계타입을 4가지로 표현한다
1. BelongsTo
2. HasOne
3. HasMany
4. BelongsToMany

먼저 BelongsTo부터 알아보자
아래와 같이 사용된다
A.BelongsTo(B)
상당히 직관적이지 않은가.
A엔티티는 B에 속해있다.
review는 store에 속해있다
Review.BelongsTo(Store)
review는 user에 속해있다.
Review.BelongsTo(User)
리뷰의 관점에서 Store와 User는 속해있는 존재이다.
그럼 Store와 User는 Review를 볼때 어떻게 표현할까

그것을 표현할때 HasMany가 사용된다.
A.HasMany(B)
A엔티티는 B엔티티를 가진다.
Store는 Review를 가지고 있다
Store.HasMany(Review)
User는 Review를 가지고 있다.
User.HasMany(Review)

그럼 저렇게 코드를 만들었을때 실제 데이터베이스에는 어떻게 반영이 될까?
데이터베이스 입장에서는
Store.HasMany(Review)이든 Review.BelongsTo(Store) 이든 결국 store와 review가 foreign key로 관계가 맺어 진다는것은 같다. 저 두가지를 나누는건 프로그램 관점으로 나누어져 있다.그럼 위의 제약조건대로 제약조건이 걸릴것이다.

ALTER TABLE M_REVIEW ADD CONSTRAINT fk_review1 FOREIGN KEY (STORE_CD) REFERENCES M_STORE (STORE_CD);

물론 실제 sql은 저렇게 안날아가고 테이블 생성시 제약조건을 걸면서 생성한다.
실제 생성된 테이블을 보면 foreign key가 있는 테이블인 review에 store_id라는 컬럼이 생성되었고 store테이블의 id와 외래키가 걸려있을것이다.
그런데 store_id라는 컬럼 이름은 어디서 온걸까
belongsTo 관계를 위한 외래 키는 [target 모델의 이름 + target 모델의 주요 키 이름] 로 자동 생성되는 것이 기본값이다.
그리고 1:n관계를 맺을시 1에 해당하는 테이블의 id컬럼을 외래키로 자동으로 맵핑한다.
만약 외래키의 컬럼이름도 직접 지정하고 싶고 1에 해당하는 테이블의 id컬럼이 아닌 다른 컬럼과 관계를 맺고 싶다면 어떻게 해야할까
HasMany와 BelongsTo의 두번째 인자로 설정할 수 있다.

Store.hasMany(Review, {foreignKey: 'storeCd', sourceKey: 'storeCd'});
Review.belongsTo(Store, {foreignKey: 'storeCd', targetKey: 'storeCd'});

foreignKey는 ..퍼짐 곧 다시 작성하겠음

profile
국물을 달라

0개의 댓글