Часто задаваемые вопросы
Эта страница переведена PageTurner AI (бета). Не одобрена официально проектом. Нашли ошибку? Сообщить о проблеме →
Как обновить схему базы данных?
Одна из основных задач TypeORM — поддерживать синхронизацию таблиц базы данных с вашими сущностями. Для этого существует два подхода:
-
Используйте
synchronize: trueв настройках источника данных:import { DataSource } from "typeorm"
const myDataSource = new DataSource({
// ...
synchronize: true,
})Эта опция автоматически синхронизирует таблицы базы данных с указанными сущностями при каждом запуске кода. Идеально подходит для разработки, но в продакшене е ё рекомендуется отключать.
-
Используйте CLI-инструменты для ручной синхронизации схемы через командную строку:
typeorm schema:syncЭта команда выполняет синхронизацию схемы.
Синхронизация схемы работает очень быстро. Если вы планируете отключать опцию synchronize в разработке из-за проблем с производительностью — сначала проверьте её скорость.
Как изменить имя столбца в базе данных?
По умолчанию имена столбцов генерируются из названий свойств сущности. Для изменения укажите опцию name в декораторе столбца:
@Column({ name: "is_active" })
isActive: boolean;
Как установить значение по умолчанию в виде функции (например, NOW())?
Опция default поддерживает функции. Если передать функцию, возвращающую строку, она будет использована как значение по умолчанию без экранирования. Пример:
@Column({ default: () => "NOW()" })
date: Date;
Как реализовать валидацию?
Валидация не входит в TypeORM, так как это отдельный процесс, не связанный напрямую с его задачами. Для валидации используйте class-validator — он идеально интегрируется с TypeORM.
Что означает "сторона владельца" в отношениях и зачем нужны @JoinColumn/@JoinTable?
Рассмотрим отношение one-to-one на примере сущностей User и Photo:
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@OneToOne()
photo: Photo
}
@Entity()
export class Photo {
@PrimaryGeneratedColumn()
id: number
@Column()
url: string
@OneToOne()
user: User
}
В этом примере отсутствует @JoinColumn, что неверно.
Почему? Потому что для создания реальной связи необходимо добавить столбец в базу данных: userId в таблице photo или photoId в user.
Но какой столбец следует создать - userId или photoId?
TypeORM не может принять решение за вас.
Чтобы принять решение, необходимо использовать @JoinColumn на одной из сторон.
@JoinColumnвPhoto→ создаст столбецuserIdв таблицеphoto@JoinColumnвUser→ создаст столбецphotoIdв таблицеuser
Сторона с @JoinColumn называется "владельцем отношения" (owner side), противоположная сторона отношения, без @JoinColumn, — "инверсной (не владеющей) стороной" (inverse/non-owner side).
Аналогично для отношений @ManyToMany: @JoinTable указывает на владеющую сторону.
В отношениях @ManyToOne/@OneToMany декоратор @JoinColumn не обязателен — таблица с @ManyToOne автоматически получает связующий столбец.
Декораторы @JoinColumn и @JoinTable также позволяют настраивать дополнительные параметры: имя связующего столбца, название junction-таблицы и т.д.
Как добавить дополнительные столбцы в таблицу связи "многие-ко-многим"?
Невозможно добавить кастомные столбцы в автоматически генерируемую junction-таблицу. Решение:
- Создайте отдельную сущность-связку
- Свяжите её с целевыми сущностями через два отношения @ManyToOne
- Добавьте нужные столбцы в сущность-связку
Результат будет аналогичен связи "многие-ко-многим". Подробнее в разделе Отношения "многие-ко-многим".
Как работать с опцией компилятора TypeScript outDir?
При использовании опции компилятора outDir не забывайте копировать ресурсы и ассеты вашего приложения в выходную директорию. В противном случае убедитесь, что пути к этим ресурсам настроены корректно.
Важно понимать, что при удалении или перемещении сущностей старые файлы оста ются в выходной директории. Например, вы создали сущность Post, затем переименовали её в Blog — файл Post.ts исчез из проекта, но Post.js останется в выходной директории. Когда TypeORM будет читать сущности из этой директории, он обнаружит обе сущности — Post и Blog, что может привести к ошибкам. Поэтому при изменении сущностей с включённой опцией outDir настоятельно рекомендуется удалять выходную директорию и перекомпилировать проект заново.
Как использовать TypeORM с ts-node?
Чтобы избежать постоянной перекомпиляции файлов, используйте ts-node. При работе с ts-node укажите сущности с расширением ts в настройках источника данных:
{
entities: [__dirname + "/entities/**/*{.js,.ts}"],
subscribers: [__dirname + "/subscribers/**/*{.js,.ts}"]
}
Если вы компилируете JavaScript-файлы в ту же директорию, где находятся TypeScript-файлы, используйте опцию компилятора outDir, чтобы избежать этой проблемы.
Для запус ка TypeORM через CLI ts-node используйте следующую команду:
npx typeorm-ts-node-commonjs schema:sync
Для проектов ESM используйте вместо этого следующую команду:
npx typeorm-ts-node-esm schema:sync
Как использовать Webpack для бэкенда?
Как использовать Webpack для бэкенда?
Webpack выдаёт предупреждения из-за отсутствующих require-выражений для всех драйверов, поддерживаемых TypeORM. Чтобы отключить предупреждения для неиспользуемых драйверов, измените конфигурационный файл Webpack.
const FilterWarningsPlugin = require('webpack-filter-warnings-plugin');
module.exports = {
...
plugins: [
// ignore the drivers you don't want. This is the complete list of all drivers -- remove the suppressions for drivers you want to use.
new FilterWarningsPlugin({
exclude: [/mongodb/, /mssql/, /mysql2/, /oracledb/, /pg/, /pg-native/, /pg-query-stream/, /react-native-sqlite-storage/, /redis/, /sql.js/, /typeorm-aurora-data-api-driver/]
})
]
};
Бандлинг файлов миграций
По умолчанию Webpack собирает всё в один файл. Это может вызвать проблемы при наличии файлов миграций, которые должны выполняться после деплоя собранного кода в production. Чтобы TypeORM мог распознать и выполнить все миграции, используйте "Object Syntax" для настройки entry исключительно для файлов миграций.
const { globSync } = require("node:fs")
const path = require("node:path")
module.exports = {
// ... your webpack configurations here...
// Dynamically generate a `{ [name]: sourceFileName }` map for the `entry` option
// change `src/db/migrations` to the relative path to your migrations folder
entry: globSync(path.resolve("src/db/migrations/*.ts")).reduce(
(entries, filename) => {
const migrationName = path.basename(filename, ".ts")
return Object.assign({}, entries, {
[migrationName]: filename,
})
},
{},
),
resolve: {
// assuming all your migration files are written in TypeScript
extensions: [".ts"],
},
output: {
// change `path` to where you want to put transpiled migration files.
path: __dirname + "/dist/db/migrations",
// this is important - we want UMD (Universal Module Definition) for migration files.
libraryTarget: "umd",
filename: "[name].js",
},
}
Кроме того, начиная с Webpack 4, при mode: 'production' файлы по умолчанию оптимизируются — включая искажение имён (mangling) для минимизации размера. Это нарушает работу миграций, поскольку TypeORM идентифицирует их по именам. Для отключения минимизации полностью добавьте:
module.exports = {
// ... other Webpack configurations here
optimization: {
minimize: false,
},
}
Если вы используете UglifyJsPlugin, вы можете указать ему не изменять имена классов или функций следующим образом:
const UglifyJsPlugin = require("uglifyjs-webpack-plugin")
module.exports = {
// ... other Webpack configurations here
optimization: {
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
keep_classnames: true,
keep_fnames: true,
},
}),
],
},
}
Убедитесь, что в настройках источника данных указаны скомпилированные файлы миграций:
// TypeORM Configurations
module.exports = {
// ...
migrations: [__dirname + "/migrations/**/*{.js,.ts}"],
}
Как использовать TypeORM в ESM-проектах?
Добавьте "type": "module" в package.json вашег о проекта, чтобы TypeORM использовал import( ... ) для загрузки файлов.
Для избежания проблем с циклическими зависимостями используйте тип-обёртку Relation для определений связей в сущностях:
@Entity()
export class User {
@OneToOne(() => Profile, (profile) => profile.user)
profile: Relation<Profile>
}
Это предотвращает сохранение типа свойства в транспилированном коде метаданных свойства, устраняя циклические зависимости.
Поскольку тип колонки уже определён через декоратор @OneToOne, дополнительная типовая информация от TypeScript не требуется.
Важно: Не используйте
Relationдля колонок, не являющихся связями