Сущности
Эта страница переведена PageTurner AI (бета). Не одобрена официально проектом. Нашли ошибку? Сообщить о проблеме →
Что такое сущность?
Сущность — это класс, который сопоставляется с таблицей базы данных (или коллекцией при использовании MongoDB).
Вы можете создать сущность, определив новый класс и пометив его декоратором @Entity():
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
@Column()
firstName: string
@Column()
lastName: string
@Column()
isActive: boolean
}
Это создаст следующую таблицу в базе данных:
+-------------+--------------+----------------------------+
| user |
+-------------+--------------+----------------------------+
| id | int | PRIMARY KEY AUTO_INCREMENT |
| firstName | varchar(255) | |
| lastName | varchar(255) | |
| isActive | boolean | |
+-------------+--------------+----------------------------+
Базовые сущности состоят из столбцов и отношений.
Каждая сущность ОБЯЗАТЕЛЬНО должна иметь первичный столбец (или столбец типа ObjectId при использовании MongoDB).
Каждая сущность должна быть зарегистрирована в настройках источника данных:
import { DataSource } from "typeorm"
import { User } from "./entities/User"
const myDataSource = new DataSource({
type: "mysql",
host: "localhost",
port: 3306,
username: "test",
password: "test",
database: "test",
entities: [User],
})
Или вы можете указать целую директорию со всеми сущностями — и все они будут загружены:
import { DataSource } from "typeorm"
const dataSource = new DataSource({
type: "mysql",
host: "localhost",
port: 3306,
username: "test",
password: "test",
database: "test",
entities: [__dirname + "/entities/**/*{.js,.ts}"],
})
Если вы хотите использовать альтернативное имя таблицы для сущности User, укажите его в @Entity: @Entity("my_users").
Чтобы установить базовый префикс для всех таблиц БД в приложении, используйте опцию entityPrefix в настройках источника данных.
Аргументы конструктора сущности должны быть необязательными, поскольку ORM создаёт экземпляры классов при загрузке из БД и не знает ваших параметров конструктора.
Подробнее о параметрах @Entity — в справочнике декораторов.
Столбцы сущности
Поскольку таблицы БД состоят из столбцов, ваши сущности тоже должны содержать столбцы.
Каждое свойство класса сущности, помеченное @Column, будет сопоставлено со столбцом таблицы БД.
Первичные столбцы
Каждая сущность должна иметь минимум один первичный столбец. Существует несколько типов первичных столбцов:
@PrimaryColumn()создаёт первичный столбец, принимающий значение любого типа. Вы можете указать тип столбца явно. Если тип не указан — он будет выведен из типа свойства. В примере ниже будет создан столбец id с типомint, значение которого нужно назначать вручную перед сохранением.
import { Entity, PrimaryColumn } from "typeorm"
@Entity()
export class User {
@PrimaryColumn()
id: number
}
@PrimaryGeneratedColumn()создаёт первичный столбец с автоматической генерацией значения через автоинкремент. Будет создан столбецintс параметрамиauto-increment/serial/sequence/identity(зависит от БД и конфигурации). Значение назначать вручную не требуется — оно генерируется автоматически.
import { Entity, PrimaryGeneratedColumn } from "typeorm"
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
}
@PrimaryGeneratedColumn("uuid")создаёт первичный столбец со значением типаuuid(уникальная строковая идентификация). Значение генерируется автоматически — назначать его вручную не требуется.
import { Entity, PrimaryGeneratedColumn } from "typeorm"
@Entity()
export class User {
@PrimaryGeneratedColumn("uuid")
id: string
}
Также поддерживаются составные первичные столбцы:
import { Entity, PrimaryColumn } from "typeorm"
@Entity()
export class User {
@PrimaryColumn()
firstName: string
@PrimaryColumn()
lastName: string
}
При сохранении сущностей через save система всегда ищет сущность в БД по заданному id (или ids).
Если id/ids найдены — соответствующая строка обновляется.
Если совпадений нет — вставляется новая строка.
Для поиска сущности по id используйте manager.findOneBy или repository.findOneBy. Пример:
// find one by id with single primary key
const person = await dataSource.manager.findOneBy(Person, { id: 1 })
const person = await dataSource.getRepository(Person).findOneBy({ id: 1 })
// find one by id with composite primary keys
const user = await dataSource.manager.findOneBy(User, {
firstName: "Timber",
lastName: "Saw",
})
const user = await dataSource.getRepository(User).findOneBy({
firstName: "Timber",
lastName: "Saw",
})
Специальные столбцы
Доступны специальные типы столбцов с дополнительной функциональностью:
-
@CreateDateColumn— специальный столбец, автоматически устанавливающийся в дату создания сущности. Значение назначать не нужно — оно устанавливается автоматически. -
@UpdateDateColumn— специальный столбец, автоматически обновляющийся при каждом вызовеsave(менеджер сущностей или репозиторий) или во времяupsertпри обновлении. Значение назначать не нужно — оно обновляется автоматически. -
@DeleteDateColumn— специальный столбец, автоматически устанавливающийся в дату мягкого удаления сущности при вызове операции soft-delete через менеджер сущностей или репозиторий. Значение назначать не нужно — оно устанавливается автоматически. При наличии этого столбца область видимости по умолчанию — «не удалённые». -
@VersionColumn— специальный столбец, автоматически увеличивающий номер версии сущности при каждомsaveилиupsertс обновлением. Значение назначать не нужно — оно обновляется автоматически.
Типы колонок
TypeORM поддерживает все распространённые типы колонок, доступные в базах данных. Типы колонок зависят от конкретной СУБД — это обеспечивает гибкость в проектировании схемы базы данных.
Тип колонки можно указать первым параметром в @Column или через опции колонки в @Column. Например:
@Column("int")
или
@Column({ type: "int" })
Если вы хотите указать дополнительные параметры типа, вы можете сделать это через опции колонки. Например:
@Column("varchar", { length: 200 })
Примечание о типе
bigint: В SQL-базах данных типbigintне совместим со стандартнымnumberи преобразуется вstring.
Тип столбца enum
Тип enum поддерживается в postgres и mysql. Доступны различные варианты определения:
Использование TypeScript enum:
export enum UserRole {
ADMIN = "admin",
EDITOR = "editor",
GHOST = "ghost",
}
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
@Column({
type: "enum",
enum: UserRole,
default: UserRole.GHOST,
})
role: UserRole
}
Поддерживаются строковые, числовые и гетерогенные перечисления.
Использование массива со значениями enum:
export type UserRoleType = "admin" | "editor" | "ghost",
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({
type: "enum",
enum: ["admin", "editor", "ghost"],
default: "ghost"
})
role: UserRoleType
}
simple-array — тип колонки
Существует специальный тип колонки simple-array для хранения примитивных массивов в одной строковой колонке.
Значения разделяются запятыми. Например:
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
@Column("simple-array")
names: string[]
}
const user = new User()
user.names = ["Alexander", "Alex", "Sasha", "Shurik"]
Будет храниться в одном столбце базы данных как значение Alexander,Alex,Sasha,Shurik.
При загрузке данных из базы данных имена вернутся в виде массива,
точно в таком же виде, в каком вы их сохранили.
Важно: Значения не должны содержать запятых.
Тип колонки simple-json
Специальный тип simple-json хранит любые значения через JSON.stringify.
Полезен при отсутствии нативного JSON-типа в базе данных. Например:
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
@Column("simple-json")
profile: { name: string; nickname: string }
}
const user = new User()
user.profile = { name: "John", nickname: "Malkovich" }
Будет храниться в отдельной колонке базы данных как значение {"name":"John","nickname":"Malkovich"}.
При загрузке данных из базы вы получите обратно ваш объект/массив/примитив с помощью JSON.parse.
Колонки с генерируемыми значениями
Вы можете создать колонку с автоматически генерируемым значением, используя декоратор @Generated. Например:
@Entity()
export class User {
@PrimaryColumn()
id: number
@Column()
@Generated("uuid")
uuid: string
}
Значение uuid будет автоматически сгенерировано и сохранено в базу данных.
Помимо "uuid" существуют типы генерации "increment", "identity" (только для Postgres 10+) и "rowid" (только для CockroachDB), однако на некоторых платформах баз данных есть ограничения для таких типов генерации (например, в некоторых БД может быть только одна автоинкрементная колонка, или автоинкремент должен быть первичным ключом).
Векторные колонки
Столбцы типа vector поддерживаются в MariaDB/MySQL, Microsoft SQL Server, PostgreSQL (через расширение pgvector) и SAP HANA Cloud, что позволяет хранить и запрашивать векторные эмбеддинги для поиска похожих объектов (similarity search) и машинного обучения.
TypeORM поддерживает оба типа колонок — vector и halfvec — в различных базах данных:
-
vector— хранит векторы как 4-байтные числа с плавающей точкой (одинарная точность)- MariaDB/MySQL: нативный тип
vector - Microsoft SQL Server: нативный тип
vector - PostgreSQL: тип
vectorчерез расширениеpgvector - SAP HANA Cloud: псевдоним для типа
real_vector
- MariaDB/MySQL: нативный тип
-
halfvec— хранит векторы как 2-байтные числа с плавающей точкой (половинная точность) для экономии памяти- PostgreSQL: тип
halfvecчерез расширениеpgvector - SAP HANA Cloud: псевдоним для типа
half_vector
- PostgreSQL: тип
Количество размерностей вектора можно указать с помощью опции length:
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number
// Vector without specified dimensions
@Column("vector")
embedding: number[] | Buffer
// Vector with 3 dimensions: vector(3)
@Column("vector", { length: 3 })
embedding_3d: number[] | Buffer
// Half-precision vector with 4 dimensions: halfvec(4) (works on PostgreSQL and SAP HANA only)
@Column("halfvec", { length: 4 })
halfvec_embedding: number[] | Buffer
}
Примечание:
- MariaDB/MySQL: Поддержка векторов доступна с MariaDB 11.7 и MySQL 9
- Microsoft SQL Server: Требуется SQL Server 2025 (17.x) или новее
- PostgreSQL: Требуется установленное расширение
pgvector(предоставляет типы данных и операторы схожести)- SAP HANA: Требуется SAP HANA Cloud (2024Q1+) и поддерживаемая версия
@sap/hana-client
Пространственные столбцы
Microsoft SQL Server, MySQL/MariaDB, PostgreSQL/CockroachDB и SAP HANA поддерживают пространственные колонки. Поддержка TypeORM для каждой СУБД незначительно отличается, особенно из-за различий в именах колонок.
MS SQL, MySQL/MariaDB и SAP HANA используют геометрические данные в формате Well-Known Text (WKT), поэтому пространственные колонки должны помечаться типом string.
import { Entity, PrimaryColumn, Column } from "typeorm"
@Entity()
export class Thing {
@PrimaryColumn()
id: number
@Column("point")
point: string
@Column("linestring")
linestring: string
}
...
const thing = new Thing()
thing.point = "POINT(1 1)"
thing.linestring = "LINESTRING(0 0,1 1,2 2)"
Для Postgres/CockroachDB см. Типы данных PostGIS
Опции колонок
Опции колонок определяют дополнительные настройки для колонок вашей сущности.
Вы можете указать опции колонки на @Column:
@Column({
type: "varchar",
length: 150,
unique: true,
// ...
})
name: string;
Список доступных опций в ColumnOptions:
-
type: ColumnType— Тип столбца. Один из типов, перечисленных выше. -
name: string— Имя столбца в таблице БД. По умолчанию генерируется из имени свойства. Можно переопределить. -
length: number— Длина типа столбца. Например, для созданияvarchar(150)укажите тип и эту опцию. -
onUpdate: string— ТриггерON UPDATE. Используется только в MySQL. -
nullable: boolean— Делает столбецNULLилиNOT NULLв БД. По умолчаниюnullable: false. -
update: boolean- Указывает, обновляется ли значение столбца при операции "save". Если false, записать значение можно только при первоначальной вставке объекта. По умолчаниюtrue. -
insert: boolean- Указывает, устанавливается ли значение столбца при первой вставке объекта. По умолчаниюtrue. -
select: boolean- Определяет, скрывать ли этот столбец по умолчанию при запросах. Приfalseданные столбца не будут возвращаться стандартным запросом. По умолчаниюselect: true. -
default: string- Задаёт значениеDEFAULTна уровне базы данных. -
primary: boolean- Помечает столбец как первичный. Аналогично использованию@PrimaryColumn. -
unique: boolean- Помечает столбец как уникальный (создаёт уникальное ограничение). -
comment: string- Комментарий к столбцу в БД. Поддерживается не всеми типами баз данных. -
precision: number- Точность для десятичных столбцов (только для exact numeric), определяющая максимальное количество хранимых цифр. Применяется в некоторых типах столбцов. -
scale: number- Масштаб для десятичных столбцов (только для exact numeric), определяющий количество цифр после запятой (не может превышать precision). Применяется в некоторых типах столбцов. -
unsigned: boolean- Добавляет атрибутUNSIGNEDк числовому столбцу. Только для MySQL. -
charset: string- Задаёт кодировку столбца. Поддерживается не всеми типами БД. -
collation: string- Задаёт правила сортировки для столбца. -
enum: string[]|AnyEnum- Для типаenum: список разрешённых значений. Можно указать массив значений или enum-класс. -
enumName: string- Определяет имя используемого enum-типа. -
asExpression: string- Выражение для generated column. Только для MySQL. -
generatedType: "VIRTUAL"|"STORED"- Тип generated column. Только для MySQL. -
hstoreType: "object"|"string"- Тип возвращаемого значения дляHSTORE. Возвращает значение как строку или объект. Только для Postgres. -
array: boolean- Для типов столбцов Postgres/CockroachDB, поддерживающих массивы (напр. int[]). -
transformer: { from(value: DatabaseType): EntityType, to(value: EntityType): DatabaseType }- Для преобразования свойств произвольного типаEntityTypeв типDatabaseType, поддерживаемый БД. Поддерживается массив трансформеров — они применяются по порядку при записи и в обратном порядке при чтении. Пример:[lowercase, encrypt]преобразует строку в нижний регистр, затем шифрует при записи; при чтении — расшифрует без изменений. -
utc: boolean- Хранить/извлекать даты в часовом поясе UTC вместо локального. Только для типаdate. По умолчаниюfalse(локальный пояс для обратной совместимости).
Важно: большинство этих опций специфичны для реляционных СУБД и недоступны в MongoDB.
Наследование сущностей
Дублирование кода можно сократить через наследование сущностей.
Например, у вас есть сущности Photo, Question, Post:
@Entity()
export class Photo {
@PrimaryGeneratedColumn()
id: number
@Column()
title: string
@Column()
description: string
@Column()
size: string
}
@Entity()
export class Question {
@PrimaryGeneratedColumn()
id: number
@Column()
title: string
@Column()
description: string
@Column()
answersCount: number
}
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number
@Column()
title: string
@Column()
description: string
@Column()
viewCount: number
}
Как видно, все они содержат общие столбцы: id, title, description. Для устранения дублирования можно создать базовый класс Content:
export abstract class Content {
@PrimaryGeneratedColumn()
id: number
@Column()
title: string
@Column()
description: string
}
@Entity()
export class Photo extends Content {
@Column()
size: string
}
@Entity()
export class Question extends Content {
@Column()
answersCount: number
}
@Entity()
export class Post extends Content {
@Column()
viewCount: number
}
Все столбцы (связи, встраиваемые объекты и т.д.) из родительских сущностей (родитель может наследовать от другой сущности) будут унаследованы и созданы в конечных сущностях.
Иерархические сущности
TypeORM поддерживает паттерны Adjacency list (Список смежности) и Closure table (Таблица замыканий) для хранения древовидных структур.
Adjacency list (Список смежности)
Простейшая модель с самоссылкой. Преимущество - простота реализации, недостаток - невозможность загрузить большое дерево целиком из-за ограничений JOIN. Пример:
import {
Entity,
Column,
PrimaryGeneratedColumn,
ManyToOne,
OneToMany,
} from "typeorm"
@Entity()
export class Category {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@Column()
description: string
@ManyToOne((type) => Category, (category) => category.children)
parent: Category
@OneToMany((type) => Category, (category) => category.parent)
children: Category[]
}
Closure table (Таблица замыканий)
Отдельная таблица для хранения отношений родитель-потомок со специальной структурой. Эффективна для чтения и записи. Подробнее в презентации Bill Karwin. Пример:
import {
Entity,
Tree,
Column,
PrimaryGeneratedColumn,
TreeChildren,
TreeParent,
TreeLevelColumn,
} from "typeorm"
@Entity()
@Tree("closure-table")
export class Category {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@Column()
description: string
@TreeChildren()
children: Category[]
@TreeParent()
parent: Category
@TreeLevelColumn()
level: number
}