왜냐하면, ORM을 사용하기로 했다. 그중에서도 많고 많은 ORM 중에 TypeORM을 사용하기로 했다.
사용하기로한 이유를 아래 차례대로 나열해 보겠습니다.
첫 번째, 데이터베이스와 상호작용하는 코드가 더 직관적인고 유지보수의 이점을 준다.
두 번째, 자동화된 데이터베이스 스키마 관리와 타입 안전성을 제공해 개발자가 더욱 생산적이고 안전하게 코드를 작성할 수 있다.
세 번째, 직접 SQL을 작성하는 경우보다, 코드의 복잡성이 줄어들며 여러 데이터베이스를 지원하여 유연성을 확보할 수 있다.
위의 세가지 이유는 여러 블로그를 읽어보며 나와 있는 내용이다. 하지만, 가장 중요한 이유 중 하나는 이것이다.
한 번도 사용해보지 않았기 때문에
사실 위의 세가지 이유는 형식적으로 작성을 할 수밖에 없습니다. 왜냐하면, 누군가는 정석적인 이유를 알아야 할 수도 있기 때문입니다. 하지만 저는 조금은 다릅니다. 전혀 와닿는 내용이 아니었는데요. 이유는 이러합니다.
한 번도 사용해보지 않았기 때문에, 코드가 더 직관적이고 유지보수의 이점을 주는지는 모르겠습니다. 그리고 스키마 관리와 타입 안전성을 제공해 더욱 생산적이고 안전하게 코드를 작성한다도 같이 알지 못합니다.
그리고 현재 직장에서는 모든 SQL 쿼리를 작성하고 있습니다. 정말로 직접 SQL 쿼리를 작성하는 경우보다, 코드의 복잡성이 줄어드는가? 그것은 아마 사용해 보면서 느껴봐야 할 것 같습니다. 그나마 와닿는 내용은 세 번째 이유이고 나머지 첫 번째, 두 번째는 잘 모르겠습니다.
그런 이유로 저는 "한 번도 사용해보지 않았기 때문에"라는 이유로 ORM을 사용해봐야 겠다는 생각이 들었습니다. 그리고 다들 쓴다는데 어떤 이유로 쓰는지 궁금하기도 했습니다(?)
그래서 저는 새로운 기술을 습득하기 전에 기술의 정의 먼저 파악하려고 합니다. 그래야 이후에 이래서 이름이 이렇게 지어졌구나를 알 수 있기 때문이죠. 이것은 저만의 학습법이기도 합니다.
ORM(Object Relational Mapping)이란 무엇인가?
Object Relational Mapping의 약자입니다. 직역하자면 객체 관계 매핑이라고 직역합니다. 역시나 와닿지 않습니다. 풀어서 설명하도록 하겠습니다. 이것은 객체와 데이터베이스의 데이터를 자동으로 매핑해 주는 도구입니다.
(* 매핑(Mapping)이란? 두 가지 혹은 그 이상의 요소를 연결하는 과정이나 이를 통해 얻어진 결과를 의미합니다.)
저는 조금은 이해가 갑니다. 그러니까, 객체를 만들어서 매핑을 시켜준다면? 데이터 베이스의 테이블을 만들어서 얘는 얘고 쟤는 쟤야를 ORM이 뚝딱 거리면서 만들어준다는 의미인것 같습니다. 상단에 있는 그림을 보아도 두 개를 연결하고 있습니다. 하지만, 항상 "~~ 같습니다."라는 말은 확신을 줄 수 없습니다. 그렇다면 어떻게 되는지 예시를 살펴보면 될 것입니다.
저는 사용자(User)와 게시물(Post) 객체를 만들도록 하겠습니다. 상황은 이러합니다. 사용자(User) 한 명은 여러 개의 게시물(Post)을 가질 수 있습니다. 이러한 내용을 TypeScript로 작성해 보겠습니다.
User Class
해당 코드를 풀어 쓰자면 이러하다. id라는 고유한 값(PK)을 갖고 있는 유저는 여러 개의 게시물(Post)을 갖고 있을 수 있다.
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToMany(() => Post, (post) => post.user)
posts: Post[];
}
Post Class
해당 코드를 풀어쓰자면 이러하다. id라는 고유한 값(PK)를 갖고 있는 게시물(Post)은 제목(title)과 내용(Content)을 갖고 있는데, 여러 개의 게시물이 하나의 User에 속해 있을 수 있다.
@Entity()
export class Post{
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column()
content: string;
@ManyToOne(() => User, (user) => user.posts)
user: User;
}
현재까지는 OneToMany, ManyToOne과 같은 데코레이터(@을 의미합니다)는 신경쓰지 말고 그냥 보도록 해보죠. 해당 데코레이터는 위에 작성된 "사용자(User) 한명은 여러 개의 게시물(Post)을 가질 수 있습니다."을 의미합니다.
이러한 작성 방식만 보아도 "개발자가 이해하기 좀 더 편하겠군.(사실 우리는 쿼리도 잘 작성할 줄 알아야 하긴 합니다.)"라는 생각을 할 수 있었습니다.
그래서 위의 내용이 ORM이 어떤 방식으로 쿼리문이 작성됐는지 보도록 하겠습니다. 좋다 좋다 하지만 너무 믿어서도 안되기 때문이지요. 아래는 쿼리 결과입니다.
User Table
CREATE TABLE "user" (
"id" PRIMARY KEY,
"name" VARCHAR(255) NOT NULL
);
Post Table
CREATE TABLE "post" (
"id" PRIMARY KEY,
"title" VARCHAR(255) NOT NULL,
"content" TEXT NOT NULL,
"userId" INTEGER,
FOREIGN KEY ("userId") REFERENCES "user"("id")
);
위의 코드를 바탕으로 데이터베이스에서 userId를 외래키(FK)로 지정해 Join이 가능하게 데이터베이스 테이블을 작성해 주었습니다. 이렇게 객체 간의 관계를 바탕으로 자동으로 테이블을 생성해 주는 것이 매핑과정이 될 것입니다.
여기까지 글이 잘 읽혔나 궁금하네요? 글을 잘 쓰고 싶으려고 노력하고 술술 읽히게끔 쉬운 글로 작성하고 싶은데 그게 그대로 전해졌을지 모르겠습니다. 앞으로 글을 써나가면서 더욱 잘 작성하도록 노력해보겠습니다.
하지만, 여기에서 끝내면 안 됩니다. 이제 이 내용이 어떻게 코드로 작성되길래? SQL을 작성하지 않아도 될까요? 그에 대한 내용을 아래에 작성하겠습니다. 코드로요.
async function main() {
const connection = await createConnection({
...
});
const userRepository = connection.getRepository(User);
const postRepository = connection.getRepository(Post);
// 새로운 유저 생성
const newUser = new User();
newUser.name = 'jaemoon';
await userRepository.save(newUser);
// 새로운 포스트 생성
const newPost = new Post();
newPost.title = 'ORM을 사용하기로 했다. 많고 많은 ORM중에 TypeORM을.';
newPost.content = '...';
newPost.user = newUser;
await postRepository.save(newPost);
// 유저의 모든 포스트 조회
const users = await userRepository.find({ relations: ['posts'] });
await connection.close();
}
역시나 getRepository와 같은 내용은 나중에 차근차근 알아보도록 해봅시다.
위의 코드 내용은 이러합니다.
새로운 유저를 생성합니다. new를 사용해 User 객체를 생성했네요? 그리고 안에 있는 name에 jaemoon을 작성해 주고 save를 통해 데이터를 저장해주었습니다. 그리고 new를 사용해 Post 객체를 생성합니다.
똑같이 내용을 작성해주고 save를 통해 데이터를 저장했습니다. 그리고 relations를 사용해 해당 포스트와 연관된 데이터를 전부 조회했습니다. 여기까지 보신다면? Query문을 한 번도 작성하지 않았음을 알 수 있죠?
이처럼 개발자는 ORM을 사용하면서 쿼리를 작성하지 않고 코드 작성을 통해서 데이터를 생성, 조회, 업데이트, 삭제할 수 있게 되었습니다. 위 코드에서는 생성(save)과 조회(find)만 존재하지만 당연히 업데이트와 삭제도 가능합니다.
여기까지 ORM과 Database 간의 매핑에 대해서 작성했습니다. 또한, 코드를 보면서 어떤 흐름으로 작성되는지 알아보았습니다. 이상 ORM의 정의와 간단한 ORM을 이용한 결괏값을 작성한 저였습니다. 감사합니다.
다음 글은 조금 더 깊은 내용을 다룰 것 같습니다. 물론 제 수준에서의 깊은 수준입니다. 그래서 왜 배우는데? 심화 편입니다.
'Project > TypeORM' 카테고리의 다른 글
[번역] OneToMany / ManyToOne Relations (0) | 2024.08.21 |
---|---|
[번역] @OneToOne Relations (0) | 2024.08.19 |
어떻게 데이터를 건드릴 수 있을까? (0) | 2024.08.14 |
왜 ORM을 사용하려고 하는데요? (0) | 2024.08.14 |
너랑 나랑 무슨 관계(relation)야? (0) | 2024.08.13 |