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 |