https://github.com/typeorm/typeorm/blob/master/docs/active-record-data-mapper.md
위 글을 읽으면서 정리한 글이다.
Flask 에서 SQLAlchemy 를 사용하면서 Data Mapper 패턴에 대해서는 잘 알고있다고 생각했는데,
막상 새로운 ORM 앞에서 주저앉는 나... 를 발견했다.
각설하고, 바로 본론으로 들어간다.
What is the Active Record pattern?
typeorm은 Active Record 패턴과 Data Mapper 패턴 모두 지원하는데,
Active Record 를 이용하면 모델 자체에 쿼리 메소드를 정의하고, 해당 메소드를 이용하여 객체를 저장/읽기/수정/삭제 한다.
간단히 정리하면 이 패턴은 모델 안에서 데이터베이스에 액세스하는 접근 방식인거다.
아래는 공식 문서에서 제공하고 있는 예시다.
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from "typeorm"
@Entity()
export class User extends BaseEntity {
@PrimaryGeneratedColumn()
id: number
@Column()
firstName: string
@Column()
lastName: string
@Column()
isActive: boolean
static findByName(firstName: string, lastName: string) {
return this.createQueryBuilder("user")
.where("user.firstName = :firstName", { firstName })
.andWhere("user.lastName = :lastName", { lastName })
.getMany()
}
}
해당 메소드 호출은 아래와 같이 진행한다.
// example how to save AR entity
const user = new User()
user.firstName = "Timber"
user.lastName = "Saw"
user.isActive = true
await user.save()
// example how to remove AR entity
await user.remove()
// example how to load AR entities
const users = await User.find({ skip: 2, take: 5 })
const newUsers = await User.findBy({ isActive: true })
const timber = await User.findOneBy({ firstName: "Timber", lastName: "Saw" })
위 예제 코드에서 생성한 정적메소드 findByName 은 아래와 같이 사용하라고 친절하게 알려준다.
const timber = await User.findByName("Timber", "Saw")
What is the Data Mapper pattern?
Data Mapper 방식을 사용하면 분리된 클래스에 쿼리 메소드를 정의한다.
NestJS 를 공부해봤다면 들어봤을 Repository 개념이 여기서 활용된다.
이 Repository 를 이용하여 객체를 저장/읽기/수정/삭제 한다.
Data Mapper 에서 내 모델, 즉 엔티티는 'dumb' 하다고 알려준다.
엔티티는 속성을 정의하는 역할만 하고 있고, 실제 기능은 repository 가 수행하는 것이다.
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
@Column()
firstName: string
@Column()
lastName: string
@Column()
isActive: boolean
}
Entity 는 위와 같이 심플하게 정의된다.
Repository 는 아래와 같이 생성하는데,
여기서 함정은 typeorm 버전 0.3.x 버전부터 EntityRepository 데코레이터는 deprecated 되었다는 점이다..^^
그래서 나는 이걸 해결하기 위해서 customRepo를 생성했어야했다.
ㅋㅋ 삽질 재밌다 즐거워요
아무튼 아래는 공식문서 예제를 가져온 것이다.
만약 customRepository 를 새로 정의해서 사용한다면
EntityRepository 데코레이션 대신 CustomRepository 를 쓰면 되겠다.
import {EntityRepository, Repository} from "typeorm";
import {User} from "../entity/User";
@EntityRepository()
export class UserRepository extends Repository<User> {
findByName(firstName: string, lastName: string) {
return this.createQueryBuilder("user")
.where("user.firstName = :firstName", { firstName })
.andWhere("user.lastName = :lastName", { lastName })
.getMany();
}
}
const userRepository = dataSource.getRepository(User)
// example how to save DM entity
const user = new User()
user.firstName = "Timber"
user.lastName = "Saw"
user.isActive = true
await userRepository.save(user)
// example how to remove DM entity
await userRepository.remove(user)
// example how to load DM entities
const users = await userRepository.find({ skip: 2, take: 5 })
const newUsers = await userRepository.findBy({ isActive: true })
const timber = await userRepository.findOneBy({
firstName: "Timber",
lastName: "Saw",
})
dataSource 로부터 repository를 가져와 해당 repo에서 모든 동작을 수행하는 것을 확인할 수 있다.
무엇을 선택하면 좋을까?
규모가 작고 간단한 애플리케이션 -> Active Record
규모가 크고 유지보수할 때 좋아야하는 애플리케이션 -> Data Mapper
'Archive > Develop' 카테고리의 다른 글
[ Flask Migrate ] Multiple head revisions are present for given argument 'head' (0) | 2022.09.20 |
---|---|
[ JavaScript ] Map & Reduce 요약 정리 (0) | 2022.09.19 |
[ 모던 자바스크립트 스터디 ] 스코프(Scope) (0) | 2022.09.18 |
[ 모던 자바스크립트 스터디 ] 함수 호출 (0) | 2022.09.18 |
[ 모던 자바스크립트 스터디 ] 함수 선언/ 함수 표현/ Function/ 화살표 함수 (0) | 2022.09.18 |