Ответ
TypeORM — это Object-Relational Mapper (ORM) для TypeScript и JavaScript, который работает в среде Node.js. Он позволяет взаимодействовать с реляционными базами данных (такими как PostgreSQL, MySQL, MariaDB, SQLite, Microsoft SQL Server) и даже с MongoDB, используя объектно-ориентированный подход: вы работаете с классами и объектами (сущностями), а TypeORM транслирует это в SQL-запросы.
Ключевые концепции и особенности:
-
Сущности (Entities): Классы, помеченные декоратором
@Entity(), которые отображаются на таблицы в БД.import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; @Entity('users') // Имя таблицы в БД export class User { @PrimaryGeneratedColumn() id: number; @Column({ type: 'varchar', length: 100 }) name: string; @Column({ unique: true }) email: string; } -
Два паттерна работы:
- Active Record: Сущность наследует от базового класса
BaseEntityи получает методы для работы с собой (save,find,remove).const user = new User(); user.name = 'Alice'; await user.save(); // Метод доступен, если User extends BaseEntity - Data Mapper: Используются отдельные классы-репозитории (
Repository), которые инкапсулируют всю логику работы с сущностью. Это считается более гибким и чистым подходом.// В сервисе const userRepository = dataSource.getRepository(User); const newUser = userRepository.create({ name: 'Bob', email: 'bob@mail.com' }); await userRepository.save(newUser);
- Active Record: Сущность наследует от базового класса
-
Связи (Relations): Легко определяются через декораторы (
@OneToMany,@ManyToOne,@ManyToMany,@OneToOne). -
Миграции (Migrations): Позволяют управлять изменениями схемы базы данных в контролируемом виде.
-
Query Builder: Мощный конструктор запросов для сложных операций.
Пример использования Data Mapper в приложении на Express + TypeORM:
// user.service.ts
import { AppDataSource } from './data-source'; // Настроенный DataSource
import { User } from '../entity/User';
export class UserService {
private userRepository = AppDataSource.getRepository(User);
async createUser(userData: Partial<User>): Promise<User> {
const user = this.userRepository.create(userData);
return await this.userRepository.save(user);
}
async findUserByEmail(email: string): Promise<User | null> {
return await this.userRepository.findOne({ where: { email } });
}
} Ответ 18+ 🔞
Блин, слушай, вот есть такая штука — TypeORM. Ну, это такой Object-Relational Mapper, если по-умному, а по-простому — инструмент, чтобы не писать SQL вручную, а работать с базой данных как с обычными классами и объектами на TypeScript или JavaScript. Под капотом он сам эту всю хуйню в SQL-запросы переводит. Поддерживает он, ядрёна вошь, почти всё: PostgreSQL, MySQL, SQLite, Microsoft SQL Server и даже MongoDB.
Основные фишки, на которых всё держится:
-
Сущности (Entities): Это просто классы, которые ты помечаешь декоратором
@Entity(). Каждый такой класс — будущая таблица в базе. Внутри описываешь колонки — и всё, магия начинается.import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; @Entity('users') // Вот так таблица в базе и назовётся export class User { @PrimaryGeneratedColumn() // Автоинкрементный ID, ёпта id: number; @Column({ type: 'varchar', length: 100 }) // Обычная строка name: string; @Column({ unique: true }) // С уникальным ключом, чтобы почты не повторялись email: string; }Создал класс — и уже почти таблица готова. Удивление пиздец, как просто.
-
А работать с этим можно двумя способами, и тут уже выбор за тобой:
-
Active Record: Твоя сущность наследуется от
BaseEntity, и тогда она сама умеет сохранять, искать и удалять себя. Как будто объект сам по себе умный.const user = new User(); user.name = 'Алиса'; await user.save(); // И всё, сохранилось! Метод прямо у объекта.Удобно для мелких проектов, но в больших может превратиться в пиздопроебибну, потому что логика работы с базой размазана по всем объектам.
-
Data Mapper: А вот это, чувак, более правильный и гибкий путь. Тут вся работа с базой идёт через отдельные штуки — репозитории (
Repository). Сущность — это просто данные, а репозиторий — это уже менеджер, который с этими данными работает. Так код чище и тестировать проще.// Где-нибудь в сервисе const userRepository = dataSource.getRepository(User); // Получаем репозиторий для User const newUser = userRepository.create({ name: 'Боб', email: 'bob@mail.com' }); // Создаём инстанс await userRepository.save(newUser); // И сохраняем через репозиторийБольшинство адекватных проектов идут этим путём. Доверия к нему больше, ебать.
-
-
Связи (Relations): Ну а как же без них? Один-ко-многим, многие-ко-многим — всё это настраивается декораторами (
@OneToMany,@ManyToOneи т.д.). TypeORM потом сам джойны строит, если правильно настроить. -
Миграции (Migrations): Овердохуища важная вещь! Это как система контроля версий, но для структуры базы данных. Хочешь добавить колонку или переименовать таблицу? Пишешь миграцию, применяешь её — и у всей команды база синхронизируется. Без этого — пиши пропало, рано или поздно.
-
Query Builder: Когда стандартных методов репозитория не хватает для какой-нибудь хитрой жопы с агрегациями и сложными условиями, на помощь приходит конструктор запросов. Мощная штука, но надо головой думать.
Вот тебе живой пример, как это может выглядеть в каком-нибудь Express-сервисе:
// user.service.ts
import { AppDataSource } from './data-source'; // Это наш уже настроенный источник данных
import { User } from '../entity/User';
export class UserService {
// Сразу получаем репозиторий для работы с пользователями
private userRepository = AppDataSource.getRepository(User);
async createUser(userData: Partial<User>): Promise<User> {
// Создаём объект пользователя из данных
const user = this.userRepository.create(userData);
// И сохраняем его в базу
return await this.userRepository.save(user);
}
async findUserByEmail(email: string): Promise<User | null> {
// Ищем одного пользователя по почте
return await this.userRepository.findOne({ where: { email } });
}
}
Короче, инструмент серьёзный. Если его освоить и не косячить с архитектурой, то жизнь с базами данных становится в разы проще. Главное — сразу приучай себя к Data Mapper и миграциям, чтобы потом не было мучительно больно.