Перейти к основному содержанию

Active Record vs Data Mapper

Неофициальный Бета-перевод

Эта страница переведена PageTurner AI (бета). Не одобрена официально проектом. Нашли ошибку? Сообщить о проблеме →

Что такое паттерн Active Record?

В TypeORM вы можете использовать как паттерн Active Record, так и Data Mapper.

При подходе Active Record вы определяете все методы запросов внутри самой модели, а сохраняете, удаляете и загружаете объекты с помощью методов модели.

Проще говоря, паттерн Active Record — это подход для доступа к базе данных из ваших моделей. Подробнее о паттерне 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
}

Все сущности Active Record должны наследовать класс 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" })

BaseEntity содержит большинство методов стандартного Repository. В большинстве случаев вам не нужно использовать Repository или EntityManager с сущностями Active Record.

Допустим, мы хотим создать функцию, возвращающую пользователей по имени и фамилии. Мы можем создать такую функцию как статический метод класса User:

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")

Что такое паттерн Data Mapper?

В TypeORM вы можете использовать как паттерн Active Record, так и Data Mapper.

При подходе Data Mapper вы определяете все методы запросов в отдельных классах, называемых "репозиториями", а сохраняете, удаляете и загружаете объекты с помощью репозиториев. В Data Mapper ваши сущности предельно просты — они только определяют свои свойства и могут содержать "простые" методы.

Проще говоря, Data Mapper — это подход для доступа к базе данных через репозитории вместо моделей. Подробнее о паттерне Data Mapper можно прочитать на Википедии.

Пример:

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number

@Column()
firstName: string

@Column()
lastName: string

@Column()
isActive: boolean
}

Пример работы с такой сущностью:

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",
})

Для расширения стандартного репозитория пользовательскими методами используйте паттерн кастомного репозитория.

Какой подход выбрать?

Решение остается за вами. Обе стратегии имеют свои преимущества и недостатки.

При разработке программного обеспечения мы всегда должны помнить о том, как будем поддерживать наши приложения. Подход Data Mapper способствует поддержке, что особенно эффективно в крупных приложениях. Подход Active Record помогает сохранять простоту, что хорошо работает в небольших приложениях.