Сущности и репозитории
Сущность (entity) — класс, который описывает таблицу: каждое свойство с декоратором становится столбцом, а каждый объект — строкой. Репозиторий — готовый объект TypeORM с методами для одной таблицы: найти, сохранить, удалить. Вместо массива из второй главы сервис статей будет работать с репозиторием.
Сущность статьи
Класс Post уже лежит в src/posts/entities/post.entity.ts. Добавьте ему декораторы TypeORM:
// src/posts/entities/post.entity.ts
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number;
@Column({ length: 120 })
title: string;
@Column('text')
content: string;
@CreateDateColumn()
createdAt: Date;
}| Декоратор | Что создаёт |
|---|---|
@Entity() | Таблицу post |
@PrimaryGeneratedColumn() | Первичный ключ, который база увеличивает сама |
@Column() | Обычный столбец; тип берётся из TypeScript |
@Column('text') | Столбец с явно указанным типом |
@CreateDateColumn() | Дату создания, заполняется автоматически |
Регистрация в модуле
Модуль статей сообщает TypeORM о своей сущности:
// src/posts/posts.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Post } from './entities/post.entity';
import { PostsController } from './posts.controller';
import { PostsService } from './posts.service';
@Module({
imports: [TypeOrmModule.forFeature([Post])],
controllers: [PostsController],
providers: [PostsService],
})
export class PostsModule {}После сохранения сервер перезапустится, и благодаря synchronize: true в файле blog.sqlite появится таблица post со столбцами id, title, content и createdAt.
Репозиторий в сервисе
forFeature() создаёт репозиторий, а декоратор @InjectRepository() внедряет его в сервис:
// src/posts/posts.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CreatePostDto } from './dto/create-post.dto';
import { Post } from './entities/post.entity';
@Injectable()
export class PostsService {
constructor(
@InjectRepository(Post)
private readonly postsRepository: Repository<Post>,
) {}
findAll(): Promise<Post[]> {
return this.postsRepository.find({ order: { createdAt: 'DESC' } });
}
async findOne(id: number): Promise<Post> {
const post = await this.postsRepository.findOneBy({ id });
if (!post) {
throw new NotFoundException(`Статья ${id} не найдена`);
}
return post;
}
create(dto: CreatePostDto): Promise<Post> {
const post = this.postsRepository.create(dto);
return this.postsRepository.save(post);
}
}Все методы репозитория асинхронные и возвращают промисы. Контроллер менять не нужно: NestJS сам дождётся промиса. Создайте статью POST-запросом, перезапустите сервер и откройте /posts — статья осталась на месте.
Основные методы репозитория
| Метод | Что делает |
|---|---|
find(options) | Список строк с условиями, сортировкой, ограничением |
findOneBy({ id }) | Одна строка или null |
create(data) | Новый объект сущности, ещё не сохранённый |
save(entity) | Вставляет новую строку или обновляет существующую |
update(id, data) | Меняет поля без загрузки объекта |
delete(id) | Удаляет строку по ключу |
count(options) | Количество строк |
Частая ошибка
Ошибка Nest can't resolve dependencies of the PostsService (?) с упоминанием PostRepository значит, что в модуле забыли TypeOrmModule.forFeature([Post]). Репозиторий существует только в модулях, которые зарегистрировали сущность. Если репозиторий нужен другому модулю, добавьте forFeature() и туда либо экспортируйте сервис, который с ним работает.