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

Миграция на версию 1

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

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

Это руководство по миграции для обновления с версии 0.3.x до 1.0.

Требования к платформе

Node.js 20+

Минимальная цель для JavaScript теперь ES2023, что требует Node.js версии 20 или новее. Если вы используете более старую версию Node.js, обновите её перед обновлением TypeORM.

Buffer заменён на Uint8Array на неподдерживаемых платформах

Полифил браузерного Buffer удалён. На неподдерживаемых платформах (браузер, Deno, Bun) бинарные данные теперь представлены как Uint8Array. Пользователи Node.js не затронуты — Buffer в Node.js расширяет Uint8Array и продолжает работать как прежде.

Изменения драйверов

MySQL / MariaDB

Опция connectorPackage удалена

Опция connectorPackage удалена вместе с поддержкой старого клиента mysql. Единственным поддерживаемым клиентом теперь является mysql2, который TypeORM будет загружать по умолчанию. Если вы использовали mysql в проекте, просто замените его на mysql2.

Значение по умолчанию для legacySpatialSupport изменено на false

Опция legacySpatialSupport теперь по умолчанию имеет значение false, что означает использование TypeORM стандартных пространственных функций ST_GeomFromText и ST_AsText, представленных в MySQL 5.7 и обязательных для MySQL 8.0+. Устаревшие функции GeomFromText и AsText были удалены в MySQL 8.0.

Если вы используете MySQL 5.6 или более раннюю версию и работаете с пространственными типами, явно установите legacySpatialSupport: true:

new DataSource({
type: "mysql",
legacySpatialSupport: true,
// ...
})

Опции колонок width и zerofill удалены

В MySQL 8.0.17 ширина отображения для целочисленных типов и атрибут ZEROFILL были объявлены устаревшими, а в MySQL 8.4 полностью удалены. TypeORM больше не поддерживает опции колонок width и zerofill. Если вы использовали эти опции, удалите их из определений колонок:

// Before
@Column({ type: "int", width: 9, zerofill: true })
postCode: number

// After
@Column({ type: "int" })
postCode: number

Если вам нужно форматирование с дополнением нулями, обрабатывайте это на уровне приложения с помощью String.prototype.padStart() или функции MySQL LPAD() в сыром запросе. Опция unsigned для целочисленных типов не затронута этим изменением.

SQLite

Пакет sqlite3 больше не поддерживается. Используйте better-sqlite3:

// Before
new DataSource({
type: "sqlite",
database: "db.sqlite",
})

// After
new DataSource({
type: "better-sqlite3",
database: "db.sqlite",
})

Опция flags удалена

Пакет sqlite3 принимал флаги открытия на уровне C (OPEN_URI, OPEN_SHAREDCACHE и т.д.). better-sqlite3 не поддерживает это — вместо этого используйте специализированные опции:

  • readonly для режима "только чтение"

  • enableWAL для режима журналирования WAL

Опция busyTimeout переименована в timeout

В пакете sqlite3 использовался busyTimeout для настройки таймаута занятости SQLite. В better-sqlite3 вместо этого используется timeout (по умолчанию: 5000 мс):

// Before
new DataSource({
type: "sqlite",
database: "db.sqlite",
busyTimeout: 2000,
})

// After
new DataSource({
type: "better-sqlite3",
database: "db.sqlite",
timeout: 2000,
})

MongoDB

TypeORM теперь требует драйвер mongodb для Node.js версии 7 или новее (^7.0.0). Поддержка драйвера mongodb версий 5 и 6 прекращена.

Устаревшие параметры подключения удалены

Следующие параметры подключения MongoDB были удалены:

Removed optionAction
appnameUse appName (camelCase) instead
fsyncUse writeConcern: { journal: true } instead
jUse writeConcern: { journal: true } instead
keepAliveRemove — always enabled since MongoDB Driver v6.0
keepAliveInitialDelayRemove — not configurable since MongoDB Driver v6.0
sslUse tls instead
sslCAUse tlsCAFile instead
sslCRLRemove — no replacement in modern driver
sslCertUse tlsCertificateKeyFile instead
sslKeyUse tlsCertificateKeyFile instead
sslPassUse tlsCertificateKeyFilePassword instead
sslValidateUse tlsAllowInvalidCertificates (inverted) instead
useNewUrlParserRemove — no-op since MongoDB Driver v4.0
useUnifiedTopologyRemove — no-op since MongoDB Driver v4.0
wUse writeConcern: { w: 1 } instead
wtimeoutUse writeConcern: { wtimeoutMS: 2500 } instead
wtimeoutMSUse writeConcern: { wtimeoutMS: 2500 } instead

Метод stats() удалён

Метод stats() удалён из MongoQueryRunner, MongoEntityManager и MongoRepository. Базовая команда collStats была объявлена устаревшей в MongoDB сервере 6.2, а метод Collection.stats() удалён в драйвере MongoDB версии 7.

Вместо этого используйте стадию агрегации $collStats. Обратите внимание, что структура ответа отличается: свойства, такие как count, size и storageSize, теперь вложены в storageStats, а не находятся на верхнем уровне.

// Before
const stats = await mongoRepository.stats()
console.log(stats.count)
console.log(stats.size)
console.log(stats.totalIndexSize)

// After — use $collStats aggregation stage
const [stats] = await dataSource.mongoManager
.aggregate(MyEntity, [{ $collStats: { storageStats: {} } }])
.toArray()
console.log(stats.storageStats.count)
console.log(stats.storageStats.size)
console.log(stats.storageStats.totalIndexSize)

Глобальные функции getMongoRepository и getMongoManager удалены

Устаревшие глобальные функции getMongoRepository() и getMongoManager() были удалены. Вместо них используйте соответствующие методы экземпляра DataSource или EntityManager:

// Before
import { getMongoManager, getMongoRepository } from "typeorm"

const manager = getMongoManager()
const repository = getMongoRepository(User)

// After
const manager = dataSource.mongoManager
const repository = dataSource.getMongoRepository(User)

Типы

Внутренние типы MongoDB (ObjectId и др.) больше не реэкспортируются из typeorm. Импортируйте их напрямую из mongodb:

// Before
import { ObjectId } from "typeorm"

// After
import { ObjectId } from "mongodb"

MS SQL Server

Параметр подключения domain удалён

Устаревшая опция domain в SqlServerConnectionCredentialsOptions была удалена. Вместо неё используйте опцию authentication с типом NTLM:

// Before
new DataSource({
type: "mssql",
domain: "MYDOMAIN",
username: "user",
password: "pass",
// ...
})

// After
new DataSource({
type: "mssql",
authentication: {
type: "ntlm",
options: {
domain: "MYDOMAIN",
userName: "user",
password: "pass",
},
},
// ...
})

SAP HANA

Несколько устаревших псевдонимов подключения SAP HANA были удалены.

  • hanaClientDriver удалён. Используйте driver.

  • pool.max удалён. Используйте pool.maxConnectedOrPooled.

  • pool.requestTimeout удалён. Используйте pool.maxWaitTimeoutIfPoolExhausted.

  • pool.idleTimeout удалён. Используйте pool.maxPooledIdleTime (в секундах).

  • pool.min, pool.maxWaitingRequests и pool.checkInterval удалены без замены.

Также обратите внимание на изменения в поведении по умолчанию в конфигурации пула:

  • pool.maxPooledIdleTime теперь по умолчанию равно 30 секундам и больше не возвращается к pool.idleTimeout.

  • pool.maxWaitTimeoutIfPoolExhausted теперь по умолчанию равно 0 и больше не возвращается к pool.requestTimeout.

Expo

Поддержка устаревшего драйвера SQLite для Expo удалена. Устаревший API был удалён Expo в SDK v52. Обновитесь до Expo SDK v52 или новее и используйте современный асинхронный API SQLite:

// Before
new DataSource({
type: "expo",
database: "db.sqlite",
})

// After — use Expo SDK v52+ with the modern async API
new DataSource({
type: "expo",
database: "db.sqlite",
driver: require("expo-sqlite"),
})

Redis (кэширование)

Удалена поддержка устаревших (v3) клиентов Redis в RedisQueryResultCache. Обновитесь до клиента Redis v4 или новее (redis, ioredis):

// Before — redis v3
import { createClient } from "redis"
const client = createClient()

// After — redis v4+
import { createClient } from "redis"
const client = createClient()
await client.connect()

Источник данных

ConnectionDataSource

DataSource заменил Connection в v0.3. Обратно совместимый псевдоним теперь удалён:

// Before
import { Connection, ConnectionOptions } from "typeorm"

const connection = await createConnection(options)
await connection.close()

// After
import { DataSource, DataSourceOptions } from "typeorm"

const dataSource = new DataSource(options)
await dataSource.initialize()
await dataSource.destroy()

По всему коду применяются следующие переименования:

BeforeAfter
ConnectionDataSource
ConnectionOptionsDataSourceOptions
BaseConnectionOptionsBaseDataSourceOptions
MysqlConnectionOptionsMysqlDataSourceOptions
(same pattern for all drivers)
connection.connect()dataSource.initialize()
connection.close()dataSource.destroy()
connection.isConnecteddataSource.isInitialized

Свойство name удалено

Устаревшее свойство name в DataSource и BaseDataSourceOptions удалено. Именованные подключения были объявлены устаревшими в v0.3 при удалении ConnectionManager. Если вы использовали name для идентификации подключений, управляйте экземплярами DataSource напрямую.

Примечание: код, читающий dataSource.name, теперь будет получать undefined вместо "default". Если вы используете это значение в логировании или логике мультитенантности, обновите соответствующим образом.

Свойство .connection в различных классах теперь .dataSource

Свойство connection в классах Driver, QueryRunner, EntityManager, QueryBuilder, EntityMetadata и *Event было переименовано в dataSource. Для EntityManager это изменение анонсировалось в версии 0.3, но фактически не было реализовано. Для упрощения перехода добавлен устаревший геттер, возвращающий то же значение, что и dataSource.

Разное

Класс ConnectionManager был удалён. Если вы использовали его для управления несколькими подключениями, создавайте и управляйте экземплярами DataSource напрямую.

ConnectionOptionsReader также упрощён: all() переименован в get() (возвращает все конфигурации массивом), а старые методы get(name) и has(name) удалены.

const reader = new ConnectionOptionsReader()

// when your ormconfig has a single data source
const [options] = await reader.get()

// when you need a specific config from multiple data sources
const allOptions = await reader.get()
const postgresOptions = allOptions.find((o) => o.type === "postgres")

Глобальные вспомогательные функции удалены

Следующие устаревшие глобальные функции были удалены:

  • createConnection / createConnections

  • getConnection

  • getConnectionManager

  • getConnectionOptions

  • getManager

  • getSqljsManager

  • getRepository

  • getTreeRepository

  • createQueryBuilder

Используйте эквивалентные методы на вашем экземпляре DataSource:

// Before
const repo = getRepository(User)
const qb = createQueryBuilder("user")

// After
const repo = dataSource.getRepository(User)
const qb = dataSource.createQueryBuilder("user")

Настройка через переменные среды удалена

Устаревший класс ConnectionOptionsEnvReader и возможность настройки подключений через переменные среды TYPEORM_CONNECTION, TYPEORM_URL и другие TYPEORM_* удалены. Формат файла ormconfig.env также больше не поддерживается. TypeORM больше не загружает автоматически файлы .env и не зависит от dotenv.

Вместо этого используйте файл конфигурации TypeScript или JavaScript:

// ormconfig.ts
export default {
type: process.env.DB_TYPE,
url: process.env.DB_URL,
// ...
}

Изменения в поведении

Значение по умолчанию для invalidWhereValuesBehavior изменено на throw

Это значительное изменение поведения, которое может привести к сбою существующих приложений во время выполнения.

Поведение по умолчанию для значений null и undefined в условиях where изменилось. Ранее такие значения молча игнорировались (свойство пропускалось). Теперь оба вызывают ошибку по умолчанию.

Данное изменение предотвращает трудноуловимые ошибки, когда запросы вида findBy({ id: undefined }) молча возвращали все строки вместо генерации ошибки.

// v0.3: silently returns all posts (null is ignored)
// v1.0: throws TypeORMError
await repository.find({ where: { text: null } })

// v0.3: silently returns all posts (undefined is ignored)
// v1.0: throws TypeORMError
await repository.find({ where: { text: undefined } })

Для сопоставления значений null используйте оператор IsNull():

import { IsNull } from "typeorm"

await repository.find({ where: { text: IsNull() } })

Чтобы восстановить предыдущее поведение, задайте параметр invalidWhereValuesBehavior в настройках источника данных:

new DataSource({
// ...
invalidWhereValuesBehavior: {
null: "ignore",
undefined: "ignore",
},
})

Эта настройка применяется ко всем высокоуровневым API — операциям поиска (find), методам изменения в репозитории/менеджере и queryBuilder.setFindOptions() (единственный затронутый метод QueryBuilder). Остальные методы QueryBuilder (.where(), .andWhere(), .orWhere()) не затрагиваются — значения null и undefined передаются как есть. Подробнее см. Обработка null и undefined.

Хеширование

Ранее TypeORM использовал npm-пакет sha.js для SHA-1 хеширования (нестандартная реализация). Теперь он заменён на встроенный модуль crypto из Node.js, а пакет uuid заменён на crypto.randomUUID().

Для браузерных сред RandomGenerator.sha1 был исправлен до стандартной реализации.

Последствия: При использовании кеша результатов запросов TypeORM существующие записи в кеше станут недействительными после обновления, поскольку хеш-функция генерирует другой вывод. Это безопасно — кеш автоматически перестроится — но возможен временный рост количества промахов кеша.

Шаблоны glob

Шаблоны glob (используемые при обнаружении файлов сущностей/миграций) теперь обрабатываются tinyglobby вместо glob. Это практически прямая замена, но в крайних случаях с раскрытием фигурных скобок или платформозависимыми разделителями путей поведение может отличаться.

Колонки

Опция readonly удалена

Устаревшая опция колонки readonly была удалена. Вместо неё используйте опцию update — обратите внимание, что она принимает противоположное значение:

// Before
@Column({ readonly: true })
authorName: string

// After
@Column({ update: false })
authorName: string

Опция unsigned в ColumnNumericOptions удалена

Устаревшее свойство unsigned в ColumnNumericOptions (используемое с перегрузками типов колонок decimal/float, например @Column("decimal", { unsigned: true })) удалено, поскольку MySQL объявил устаревшим UNSIGNED для нецелочисленных числовых типов. Опция unsigned в ColumnOptions для целочисленных типов не затронута.

Связи

nullable: false теперь использует INNER JOIN

Связи с пометкой nullable: false теперь используют INNER JOIN вместо LEFT JOIN при загрузке через relations, eager loading или параметры поиска. Это касается только типов связей, владеющих колонкой соединения (ManyToOne и owning-side OneToOne).

Это семантически корректно, поскольку ненулевой внешний ключ гарантирует существование связанной сущности и позволяет оптимизатору СУБД строить более эффективные планы запросов.

Потенциально критичное изменение: Если ваша база содержит строки, нарушающие ограничение NOT NULL (например, "осиротевшие" внешние ключи или nullable: false установлено, но колонка фактически nullable в БД), эти строки будут исключены из результатов запросов. Проверьте целостность данных или измените связь на nullable: true при необходимости.

// INNER JOIN — related entity is guaranteed to exist
@ManyToOne(() => User, { nullable: false })
author: User

// LEFT JOIN — related entity may not exist (default)
@ManyToOne(() => User)
optionalEditor: User

Связи OneToMany, ManyToMany и обратные OneToOne всегда используют LEFT JOIN независимо от настройки nullable, поскольку эти типы связей не имеют колонки соединения в текущей таблице.

Исключение для soft-delete: Если связанная сущность содержит @DeleteDateColumn, используется LEFT JOIN даже для связей с nullable: false (если не установлен withDeleted: true). Это предотвращает фильтрацию родительских строк при наличии soft-удалённых связанных сущностей.

Репозиторий

findOneById

Устаревший метод findOneById удалён из EntityManager, Repository, BaseEntity, MongoEntityManager и MongoRepository. Используйте вместо него findOneBy:

// Before
const user = await manager.findOneById(User, 1)
const user = await repository.findOneById(1)
const user = await User.findOneById(1)

// After
const user = await manager.findOneBy(User, { id: 1 })
const user = await repository.findOneBy({ id: 1 })
const user = await User.findOneBy({ id: 1 })

Для MongoDB-сущностей с @ObjectIdColumn() метод findOneBy работает аналогично — TypeORM автоматически преобразует имя свойства в _id.

findByIds удалён

Устаревший метод findByIds был удалён из EntityManager, Repository и BaseEntity. Вместо него используйте findBy с оператором In:

// Before
const users = await repository.findByIds([1, 2, 3])

// After
import { In } from "typeorm"

const users = await repository.findBy({ id: In([1, 2, 3]) })

exist переименован в exists

Устаревший метод Repository.exist() был удалён. Вместо него используйте exists() — поведение идентично:

// Before
const hasUsers = await userRepository.exist({ where: { isActive: true } })

// After
const hasUsers = await userRepository.exists({ where: { isActive: true } })

AbstractRepository, @EntityRepository и getCustomRepository удалены

Класс AbstractRepository, декоратор @EntityRepository и метод getCustomRepository() удалены. Они были объявлены устаревшими в v0.3 в пользу Repository.extend():

// Before
@EntityRepository(User)
class UserRepository extends AbstractRepository<User> {
findByName(name: string) {
return this.repository.findOneBy({ name })
}
}
const userRepo = dataSource.getCustomRepository(UserRepository)

// After
const UserRepository = dataSource.getRepository(User).extend({
findByName(name: string) {
return this.findOneBy({ name })
},
})

Следующие классы ошибок также были удалены: CustomRepositoryDoesNotHaveEntityError, CustomRepositoryCannotInheritRepositoryError, CustomRepositoryNotFoundError.

Декоратор @RelationCount и метод loadRelationCountAndMap удалены

Декоратор @RelationCount и метод SelectQueryBuilder.loadRelationCountAndMap() были удалены. Вместо них используйте @VirtualColumn или подзапрос в вашем построителе запросов:

// Before
@RelationCount((post: Post) => post.categories)
categoryCount: number

// After — use @VirtualColumn with a sub-query
// Replace the junction table name and column names to match your schema
@VirtualColumn({
query: (alias) =>
`SELECT COUNT(*) FROM post_categories_category WHERE postId = ${alias}.id`,
})
categoryCount: number

Параметры поиска

Опция join удалена

Устаревшее свойство join в FindOneOptions и FindManyOptions удалено вместе с интерфейсом JoinOptions.

leftJoinAndSelectrelations

Если вы использовали leftJoinAndSelect, замените его на синтаксис объекта relationsrelations всегда выполняет LEFT JOIN с выборкой, что эквивалентно:

// Before
const posts = await repository.find({
join: {
alias: "post",
leftJoinAndSelect: {
categories: "post.categories",
author: "post.author",
},
},
})

// After
const posts = await repository.find({
relations: { categories: true, author: true },
})

Все остальные типы соединений → QueryBuilder

Опция relations поддерживает только LEFT JOIN с выборкой. Если вы использовали innerJoinAndSelect, innerJoin или leftJoin (без выборки), перейдите на QueryBuilder API:

// Before — innerJoinAndSelect
const posts = await repository.find({
join: {
alias: "post",
innerJoinAndSelect: {
categories: "post.categories",
},
},
})

// After — QueryBuilder with innerJoinAndSelect
const posts = await repository
.createQueryBuilder("post")
.innerJoinAndSelect("post.categories", "categories")
.getMany()

// Before — leftJoin (without select)
const posts = await repository.find({
join: {
alias: "post",
leftJoin: {
categories: "post.categories",
},
},
where: { categories: { isRemoved: false } },
})

// After — QueryBuilder with leftJoin
const posts = await repository
.createQueryBuilder("post")
.leftJoin("post.categories", "categories")
.where("categories.isRemoved = :isRemoved", { isRemoved: false })
.getMany()

Это различие важно на практике. Например, PostgreSQL и CockroachDB не разрешают FOR UPDATE на nullable-стороне внешнего соединения, поэтому запросам с блокировкой и связями могут потребоваться INNER JOIN:

// Before — innerJoinAndSelect + lock
const post = await repository.findOne({
join: {
alias: "post",
innerJoinAndSelect: {
categories: "post.categories",
},
},
lock: { mode: "pessimistic_write", tables: ["category"] },
})

// After — QueryBuilder with innerJoinAndSelect + lock
const post = await repository
.createQueryBuilder("post")
.innerJoinAndSelect("post.categories", "categories")
.setLock("pessimistic_write", undefined, ["categories"])
.getOne()

Блокировка с вложенными связями → QueryBuilder

Опция relations не может использоваться с пессимистичной блокировкой на соединённых таблицах, поскольку relations всегда использует LEFT JOIN, а PostgreSQL/CockroachDB отвергают FOR UPDATE на nullable-стороне внешних соединений. Используйте QueryBuilder с innerJoinAndSelect вместо этого:

// Before — nested relations + lock via find options
const post = await repository.findOne({
where: { id: 1 },
join: {
alias: "post",
innerJoinAndSelect: {
categories: "post.categories",
images: "categories.images",
},
},
lock: { mode: "pessimistic_write", tables: ["images"] },
})

// After — QueryBuilder with innerJoinAndSelect + lock
const post = await repository
.createQueryBuilder("post")
.innerJoinAndSelect("post.categories", "categories")
.innerJoinAndSelect("categories.images", "images")
.where("post.id = :id", { id: 1 })
.setLock("pessimistic_write", undefined, ["images"])
.getOne()

Обратите внимание, что блокировка основной таблицы по-прежнему работает с relations — только блокировка присоединённых таблиц требует использования QueryBuilder с внутренними соединениями (inner joins).

Синтаксис select на основе строк удалён

Устаревший синтаксис массивов строк для опции select в методах поиска удалён. Вместо него используйте синтаксис объектов:

// Before
const users = await repository.find({
select: ["id", "name"],
})

// After
const users = await repository.find({
select: { id: true, name: true },
})

Удалённый тип — FindOptionsSelectByString.

Синтаксис relations на основе строк удалён

Устаревший синтаксис массивов строк для опции relations в методах поиска удалён. Вместо него используйте синтаксис объектов:

// Before
const users = await repository.find({
relations: ["profile", "posts"],
})

// After
const users = await repository.find({
relations: { profile: true, posts: true },
})

Удалённый тип — FindOptionsRelationByString.

Построитель запросов

printSql удалён

Метод printSql() в конструкторах запросов удалён. Он был избыточным, так как все выполняемые запросы автоматически логируются через настроенный логгер при включённом логировании запросов. Вместо этого используйте getSql() или getQueryAndParameters() для проверки сгенерированного SQL:

// Before
const users = await dataSource
.getRepository(User)
.createQueryBuilder("user")
.where("user.id = :id", { id: 1 })
.printSql()
.getMany()

// After — inspect SQL before executing
const qb = dataSource
.getRepository(User)
.createQueryBuilder("user")
.where("user.id = :id", { id: 1 })

console.log(qb.getSql())
// or: const [sql, params] = qb.getQueryAndParameters()

const users = await qb.getMany()

Для автоматического логирования всех выполняемых запросов включите логирование запросов в вашем DataSource:

new DataSource({
// ...
logging: ["query"],
})

onConflict удалён

Метод onConflict() в InsertQueryBuilder удалён. Он принимал сырые SQL-строки, зависевшие от драйвера и склонные к ошибкам. Вместо него используйте orIgnore() или orUpdate():

// Before
await dataSource
.createQueryBuilder()
.insert()
.into(Post)
.values(post)
.onConflict(`("id") DO NOTHING`)
.execute()

// After
await dataSource
.createQueryBuilder()
.insert()
.into(Post)
.values(post)
.orIgnore()
.execute()

// Before
await dataSource
.createQueryBuilder()
.insert()
.into(Post)
.values(post)
.onConflict(`("id") DO UPDATE SET "title" = :title`)
.setParameter("title", post.title)
.execute()

// After
await dataSource
.createQueryBuilder()
.insert()
.into(Post)
.values(post)
.orUpdate(["title"], ["id"])
.execute()

Перегрузка объекта в orUpdate удалена

Объектная перегрузка orUpdate(), принимающая { columns?, overwrite?, conflict_target? }, была удалена. Вместо неё используйте перегрузку на основе массива:

// Before
.orUpdate({ conflict_target: ["date"], overwrite: ["title"] })

// After
.orUpdate(["title"], ["date"])

setNativeParameters удалён

// Before
qb.setNativeParameters({ key: "value" })

// After
qb.setParameters({ key: "value" })

Внутреннее свойство QueryExpressionMap.nativeParameters также удалено. Если у вас есть пользовательский подкласс QueryBuilder, обращающийся к expressionMap.nativeParameters, переключитесь на expressionMap.parameters.

Псевдоним типа WhereExpression удалён

// Before
import { WhereExpression } from "typeorm"

// After
import { WhereExpressionBuilder } from "typeorm"

replacePropertyNames удалён

Устаревший защищённый метод replacePropertyNames() удалён. Он не выполнял действий, так как замена имён свойств была перенесена в обработку конца запроса через replacePropertyNamesForTheWholeQuery(). Если вы переопределяли этот метод в пользовательском подклассе QueryBuilder, ваша реализация больше не будет вызываться.

Устаревшие режимы блокировки удалены

// Before
.setLock("pessimistic_partial_write")

// After
.setLock("pessimistic_write")
.setOnLocked("skip_locked")

// Before
.setLock("pessimistic_write_or_fail")

// After
.setLock("pessimistic_write")
.setOnLocked("nowait")

То же относится к опциям поиска (find options):

// Before
{ lock: { mode: "pessimistic_partial_write" } }

// After
{ lock: { mode: "pessimistic_write", onLocked: "skip_locked" } }

// Before
{ lock: { mode: "pessimistic_write_or_fail" } }

// After
{ lock: { mode: "pessimistic_write", onLocked: "nowait" } }

Миграции

getAllMigrations удалён

Устаревший метод getAllMigrations() удалён из MigrationExecutor. Вместо него используйте getPendingMigrations() или getExecutedMigrations(), либо обращайтесь напрямую к dataSource.migrations для получения списка зарегистрированных классов миграций:

// Before
const migrations = await migrationExecutor.getAllMigrations()

// After — depending on what you need
const pending = await migrationExecutor.getPendingMigrations()
const executed = await migrationExecutor.getExecutedMigrations()
const registered = dataSource.migrations

Свойства QueryRunner.loadedTables и loadedViews удалены

// Before
const tables = queryRunner.loadedTables
const views = queryRunner.loadedViews

// After
const tables = await queryRunner.getTables()
const views = await queryRunner.getViews()

Примечание: замены являются асинхронными методами, а не синхронными свойствами.

Система контейнера

Устаревшая интеграция с IoC-контейнером удалена: useContainer(), getFromContainer(), ContainerInterface, ContainedType и UseContainerOptions.

TypeORM больше не имеет встроенной поддержки IoC-контейнера. Пакеты typeorm-typedi-extensions и typeorm-routing-controllers-extensions также стали несовместимы. В следующих разделах описана миграция в зависимости от вашей конфигурации.

Подписчики (subscribers) и миграции с зависимостями

TypeORM всегда создаёт экземпляры подписчиков и миграций с помощью конструктора без аргументов, поэтому вы не можете передавать предварительно созданные экземпляры. Если вашим миграциям нужен доступ к сервисам, используйте DataSource (доступный через queryRunner.dataSource) внутри самой миграции:

// Before
import { useContainer } from "typeorm"
import { Container } from "typedi"
useContainer(Container)

// After — access dependencies via the DataSource inside the migration
export class MyMigration1234 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
const repo = queryRunner.dataSource.getRepository(User)
// ...
}
}

Доступ к репозиториям и EntityManager

Если вы ранее использовали typeorm-typedi-extensions для внедрения EntityManager или репозиториев в сервисы, вместо этого напрямую используйте DataSource:

// Before (with typeorm-typedi-extensions)
import { InjectManager, InjectRepository } from "typeorm-typedi-extensions"

class UserService {
@InjectManager()
private manager: EntityManager

@InjectRepository(User)
private userRepository: Repository<User>
}

// After — access from the DataSource instance
class UserService {
private manager: EntityManager
private userRepository: Repository<User>

constructor(dataSource: DataSource) {
this.manager = dataSource.manager
this.userRepository = dataSource.getRepository(User)
}
}

Использование с DI-фреймворком

Если вы используете DI-фреймворк, зарегистрируйте DataSource (или его репозитории) как провайдеры в вашем контейнере:

// typedi example
import { DataSource } from "typeorm"
import { Container } from "typedi"

const dataSource = new DataSource({
/* ... */
})
await dataSource.initialize()
Container.set(DataSource, dataSource)
Container.set("UserRepository", dataSource.getRepository(User))

NestJS

Пользователи NestJS не затронуты — пакет @nestjs/typeorm имеет собственную интеграцию, не зависящую от удалённой системы контейнеров TypeORM. Однако @nestjs/typeorm v10 и текущая v11.0.0 пытаются зарегистрировать удалённый класс Connection и завершатся с ошибкой при запуске. Убедитесь, что вы используете версию @nestjs/typeorm с исправлением совместимости с TypeORM v1.

Прочие внутренние удаления

Следующие внутренние API были удалены. Это повлияет на вас только в том случае, если вы разрабатывали собственные драйверы, расширяли QueryBuilder или использовали низкоуровневые API метаданных:

RemovedReplacement
EntityMetadata.createPropertyPath() (static)Removed with no public replacement
DriverUtils.buildColumnAlias()Use DriverUtils.buildAlias()
Broadcaster.broadcastLoadEventsForAll()No replacement — use individual event subscribers
QueryExpressionMap.nativeParametersUse QueryExpressionMap.parameters