TypeORM을 사용하면 따로 SQL 쿼리문을 쓰지 않아도 되는가 라는 의문이 있다. 그럼 어떤 상황일때 쿼리문을 써주는게 좋을지 알아보자.
SELECT
users.id,
users.name,
orders.total,
products.name
FROM
users
JOIN
orders ON users.id = orders.user_id
JOIN
order_items ON orders.id = order_items.order_id
JOIN
products ON order_items.product_id = products.id
WHERE
users.active = true AND orders.status = 'completed';
위 쿼리는 여러 테이블을 조인하여 조건에 맞는 데이터를 조회하는 예시이다.
import { createQueryBuilder } from 'typeorm';
import { User } from './entity/User';
import { Order } from './entity/Order';
import { OrderItem } from './entity/OrderItem';
import { Product } from './entity/Product';
const users = await createQueryBuilder('user')
.select(['user.id', 'user.name', 'order.total', 'product.name'])
.from(User, 'user')
.innerJoin(Order, 'order', 'user.id = order.user_id')
.innerJoin(OrderItem, 'orderItem', 'order.id = orderItem.order_id')
.innerJoin(Product, 'product', 'orderItem.product_id = product.id')
.where('user.active = :active', { active: true })
.andWhere('order.status = :status', { status: 'completed' })
.getMany();
위 TypeORM 코드에서 동일한 조인 작업을 수행하고 있지만, 코드가 길고 복잡해졌다.
import { getManager } from 'typeorm';
const entityManager = getManager();
const users = await entityManager.query(`
SELECT
users.id,
users.name,
orders.total,
products.name
FROM
users
JOIN
orders ON users.id = orders.user_id
JOIN
order_items ON orders.id = order_items.order_id
JOIN
products ON order_items.product_id = products.id
WHERE
users.active = true AND orders.status = 'completed'
`);
TypeORM에서 복잡한 조인 쿼리르 작성하려면 여러 번의
innerJoin및where조건을 체인 형태로 연결해야 한다. 이는 가독성을 떨어뜨리고, 유지보수를 어렵게 만들 수 있다. 반면, 직접 SQL 쿼리를 작성하면 더 간결하고 명확하게 원하는 작업을 수행할 수 있다.
ORM이 생성하는 쿼리가 비효율적일 때, 직접 최적화된 SQL 쿼리를 사용하는 것이 필요할 수 있다. 특히 대량의 데이터를 일괄 삽입해야 하는 경우이다.
INSERT INTO users (name, email)
VALUES
('John Doe', 'john@example.com'),
('Jane Smith', 'jane@example.com'),
('Alice Brown', 'alice@example.com');
import { getRepository } from 'typeorm';
import { User } from './entity/User';
const userRepository = getRepository(User);
const users = [
{ name: 'John Doe', email: 'john@example.com' },
{ name: 'Jane Smith', email: 'jane@example.com' },
{ name: 'Alice Brown', email: 'alice@example.com' }
];
await userRepository.save(users);
두 코드 모두 여러 개의 사용자 데이터를 데이터베이스에 삽입하는 역할을 하지만, 실제 동작 방식에는 차이가 있다.
엔티티 매핑 및 데이터 검증
save 메서드 : 엔티티 매핑 및 데이터 검증을 자동으로 수행한다. 데이터베이스 테이블 구조와 TypeScript 코드 간의 일관성을 유지한다.성능
save 메서드 : 성능 최적화를 위해 여러 레코드를 한 번에 처리할 수 있지만, 내부적으로 여러 INSERT 쿼리를 실행할 수 있다.import { getManager } from 'typeorm';
const entityManager = getManager();
await entityManager.query(`
INSERT INTO users (name, email)
VALUES
('John Doe', 'john@example.com'),
('Jane Smith', 'jane@example.com'),
('Alice Brown', 'alice@example.com');
`);
TypeORM의 save 메서드는 편리하고 대부분의 사용 사례에서 잘 동작하지만, 대량 데이터를 삽입 할 때는 성능이 떨어질 수 있다. 이 경우 직접 SQL 쿼리를 사용하여 일괄 삽입하는 것이 더 효율적일 수 있다.