약자인데 풀명칭으로는 Object Relational Mapping
즉 객체의 형태를 데이터베이스에 매핑해주는 것을 이야기한다.
쉽게 생각해서 과거에는
SELECT p.* , GROUP_CONCAT(t.names order by t.id) AS tagname ,GROUP_CONCAT(t.id order by t.id) AS tagid FROM post p Join post_post_tags_post_tag pt On p.post_id =pt.postPostId Join post_tag t On pt.postTagId = t.id where updateat > :sql_last_value group by p.post_id order by updateat asc
이런식으로 쿼리문
을 작성했는데 이것을 조금 더 유저친화적으로 사용할 수 있도록 만들어 준 것이다.
그리고 TypeORM 웹관련에서 조금 더 명확하게 쓸 수 있는 ORM으로 만들어진 것을 이야기한다.
사실 나는 타입ORM으로 코드를 치고 있지만 생각보다 기능이 엄청 많아서 많은 것을 알지는 못한다.
그래도 일반적을 많이 사용하는 것들은 나열 할 수 있을 것 같아서 올려본다.
다양한 사용법이 존재하지만, 역시 제일 쉬운 것들은
생성 create save
읽기 find, findOne
수정 update
삭제 delete가 있다.
물론 이 외에도 엄청나게 많은 기능들이 존재하는데, 아직까지는 세밀하게 접근해서 공부를 해보진 못했다.
예를 들어 페이징에서는 findAndCount인가 다른 것을 써야한다고 들었는데
내가 써본바로는 그냥 Find에 skip이랑 take만 써도 쓸 수 있어서 긴가민가하는 상황이다(.....)
새로운 라이브러리를 쓰는 경우도 있다던데 그냥 스킵 테이크만 써도 잘...잘나오던데?
간단한 명령어라고 해야할지, 전용 기능이라고 해야할지 명확하게 구분을 못하겠는데 저런 기능들이 존재한다.
물론 단점이 있다. 조인되어있는 구조가 복잡해질수록 코드가 상당히 복잡해지고
nest와 함께 쓸 경우 의존성때문에 빨간색 에러를 보기 쉽상이라는 것이다.
그래서 결국 로우쿼리를 사용하게 되는 상황이 온다.
작업을 하다보면 기가막히게 의존성 주입이 안됐다고 빨간줄을 보는 경우가 있다.
왜냐하면 TypeORM으로 DB를 접근하기 위해서는 import를 받아와야하는데 (아래 사진처럼)
이렇게 가져오는 경우에는 생성자에 주입을 받기 때문에 모듈에 import도 수정을 해야하고
심지어 관계가 복잡하게 엮여있다면 모조리 다 주입을 받아줘야하는 미칠 상황이 온다(진짜 미친거아니냐고)
그래서 그것을 완화시키는 방법이기도 하고, 현재 작업하는 곳은 user service인데 2중 3중으로 조인된 관계를 가져올 경우 쿼리빌더의 활용성이 늘어난다.
await getConnection() .createQueryBuilder() .update(ProductInfo) .set({ volume: () => `volume-${readata[i].volume}` }) .where({ name: readata[i].product.name }) .execute(); }
이것은 cart service에서 사용한 것인데 두단계 점프가 된 관계를 가져오고 있다.
cart 속에는 Product가 1:N으로 묶여있고
Product와 ProductInfo가 1:1으로 묶여있는데 위에 기본명령어로 가져오려면 과정이 상당히 복잡해진다.
하지만 쿼리빌더를 사용할 경우에는 수정조차도 손쉽게 할 수 있다.
(위의 코드는 장바구니에서 결제가 완료되면 물품 상세 테이블의 재고가 판매 수량만큼 줄어드는 코드다.)
물론 처음에는 사용법이 raw query에 가깝기 때문에 정말 어려웠는데 지금은 어느정도 활용은 할 수 있는 단계정도가 된 것 같다.
이것은 트랜잭션을 관리할 수 있게하는 메소드다.
아예 따로 한 장을 할애할 예정이기에 링크로 대신한다
이만큼 다양한 기능이 있어서 다른 ORM을 써보지 못했기 때문에 더더욱 고민이 든다.
어떻게든 또 배우면 되긴 하겠지만, 쿼리문이 참 어려운데 과거의 개발자들이 너무 대단하다는 생각이 들 따름이다..