모델 안에서 쿼리 메서드를 정의하고, 이 메서드로 CRUD 작업 수행
요약하면 데이터베이스와의 상호작용을 모델로 통합하는 것
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
}
BaseEntity를 상속받으면 내부에 알아서 메서드가 들어간다.
// 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" })
액티브 레코드 방식은 레포지토리에서 사용되는 표준적인 메서드가 들어가 있으니까 간단하게 쓰기는 좋다!
그리고 만약 액티브 레코드에서 지원하지 않는 메서드라면 모델 안에서 메서드 만들면 된다.
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()
}
}
// 이렇게 쓸 수 있음
const timber = await User.findByName("Timber", "Saw")
쿼리 메서드를 레포지토리라는 별도 분리된 클래스에 정의한다.
데이터베이스와의 통신은 레포지토리를 통해서만 한다.
이 패턴에서 모델은 dumb하다. (쿼리 메서드 없이 간단하다. 그냥 모델은 구조만 정의한다.)
아니면 약간의 더미 메서드를 가질 수 있다.
더미 메서드를 갖는 다는 건, 엔터티 내에서는 구체적인 기능을 수행하지 않거나,
아주 기본적인 기능을 수행하는 메서드만 포함한다.
이런 메서드들은 대체포 테스트 용도거나, 특정 인퍼페이스 만족을 위해 최소한으로만 구현한다.
모델 대신에 레포지토리가 디비와 통신하는 역할을 갖는 것
내가 지금까지 사용하던 방식이었다!
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",
})
정답은 없다.
액티브 레코드는 간단하다. 간단하다는 것은 유지 보수성이 높다는 걸 의미한다.(단순함)
데이터 맵퍼는 유지보수성 좋으며, 대규모 앱에서 더 효율적이다.(관심사의 분리)