Data Mapper
데이터 매퍼(Data Mapper) 패턴은 데이터베이스와 애플리케이션 객체 사이의 매핑을 분리하여, 데이터베이스 작업을 전담하는 별도의 레포지토리(Repository)나 매퍼 클래스를 사용한다. 이 패턴에서는 엔티티 클래스는 데이터베이스 작업을 직접 수행하지 않고, 매퍼가 데이터베이스와의 상호작용을 담당한다.
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; @Entity() export class User { @PrimaryGeneratedColumn() id: number; @Column() name: string; @Column() age: number; } // Repository를 사용하여 데이터베이스 작업 수행 import { EntityRepository, Repository } from 'typeorm'; @EntityRepository(User) export class UserRepository extends Repository<User> { // 추가적인 데이터베이스 작업 메서드를 정의할 수 있습니다. }
// 추가적인 데이터베이스 작업 메서드를 정의할 수 있습니다. import { EntityRepository, Repository } from 'typeorm'; import { User } from './user.entity'; @EntityRepository(User) export class UserRepository extends Repository<User> { // 사용자 이름으로 사용자 찾기 async findByName(name: string): Promise<User[]> { return this.createQueryBuilder('user') .where('user.name = :name', { name }) .getMany(); } // 특정 나이 이상인 사용자 찾기 async findByMinAge(age: number): Promise<User[]> { return this.createQueryBuilder('user') .where('user.age >= :age', { age }) .getMany(); } // 사용자 나이 업데이트 async updateUserAge(userId: number, newAge: number): Promise<void> { await this.createQueryBuilder() .update(User) .set({ age: newAge }) .where('id = :id', { id: userId }) .execute(); } // 사용자 삭제 (Soft Delete 사용) async softDeleteUser(userId: number): Promise<void> { await this.updateUserAge(userId, null); // age를 null로 설정하거나 다른 Soft Delete 전략을 사용할 수 있습니다. } }
- Repository라는 별도의 클래스에서 모든 쿼리 방법을 정의하고, 리포지토리를 사용하여 개체를 저장, 제거 및 로드할 수 있다.
- Data Mapper에서 entity는 매우 멍청하다. 속성을 정의할 뿐이고 일부 "더미 같은" 방법을 가지고 있을 수 있다.
- 모델 대신 저장소 내에서 데이터베이스에 액세스 할 수 있는 접근 방식이다
Active Record
액티브 레코드(Active Record) 패턴은 엔티티 클래스가 데이터베이스 작업을 직접 수행하는 방식이다. 엔티티 클래스는 데이터베이스의 레코드와 직접적으로 연관되며, CRUD 작업을 직접 수행할 수 있는 메서드를 포함한다.
import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from 'typeorm'; @Entity() export class User extends BaseEntity { @PrimaryGeneratedColumn() id: number; @Column() name: string; @Column() age: number; // CRUD 작업 메서드 (예: find, save, remove) BaseEntity에서 제공됨 } // 데이터베이스 작업 수행 const user = new User(); user.name = 'John Doe'; user.age = 30; await user.save(); // 데이터베이스에 저장
// CRUD 작업 메서드 (예: find, save, remove) BaseEntity에서 제공됨 // 사용자 생성 const newUser = User.create({ name: 'John Doe', age: 30 }); await newUser.save(); // save 메서드를 사용하여 데이터베이스에 저장 // 사용자 조회 const user = await User.findOne({ where: { name: 'John Doe' } }); // findOne 메서드를 사용하여 특정 조건의 사용자 조회 // 사용자 목록 조회 const users = await User.find(); // find 메서드를 사용하여 모든 사용자 목록 조회 // 사용자 업데이트 await User.update({ name: 'John Doe' }, { age: 31 }); // update 메서드를 사용하여 특정 조건의 사용자 정보 수정 // 사용자 삭제 await User.delete({ name: 'John Doe' }); // delete 메서드를 사용하여 특정 조건의 사용자 삭제 // 소프트 삭제 (삭제 플래그를 사용) await User.softRemove({ id: 1 }); // softRemove 메서드를 사용하여 사용자 소프트 삭제
- Ruby on Rails, Django는 Active Record를 사용한다.
- 모델 자체 내에서 모든 쿼리 방법을 정의하고 모델 방법을 사용하여 개체를 저장, 제거 및 로드할 수 있다.
- 모델 내에서 데이터베이스에 액세스할 수 있는 접근 방식이다.
어떤 것을 선택해야 할까?
Active Record
단순함을 유지하는데 도움,소규모 앱에서 유용
- 데이터 접근 로직과 비즈니스 로직이 결합된 상태.
- 간단하고 직관적이다.
Data Mapper
유지 보수성에 도움이 됨, 대규모 앱에서 유용
- 데이터 접근 로직과 비즈니스 로직이 분리된 형태.
- 유연하고, 복잡한 도메인 로직을 가진 대규모 어플리케이션에 적합
NestJS에서는 Data Mapper 패턴을 사용하는 장점
- TypeORM 개발 환경에서 Repository를 사용하는 모듈을 쓸 수 있기 때문
- Repository를 사용하면 어디서든지 접근 가능하다.
- 구현하는 서비스에서 접근이 가능하고 테스팅할 때도 접근이 가능하다.
- NestJS의 경우에는 자동으로 Repository를 사용할 수 있도록 클래스에 자동으로 준비해 준다.
'Database > TypeORM' 카테고리의 다른 글
| EntityRepository - deprecated 되었다. (0) | 2024.08.02 |
|---|---|
| TypeORM의 Entity (0) | 2024.07.29 |
| TypeORM에서 제공하는 특별한 데코레이터 , 엔티티의 생성 및 수정 일자를 자동으로 관리 (0) | 2024.07.29 |
| TypeORM의 Listener (0) | 2024.07.29 |
| TypeORM 이란 (0) | 2024.07.29 |