Migración a v1
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
Esta es la guía de migración para actualizar desde la versión 0.3.x a la 1.0.
Requisitos de la plataforma
Node.js 20+
El objetivo mínimo de JavaScript ahora es ES2023, lo que requiere Node.js 20 o superior. Si estás usando una versión anterior de Node.js, actualízala antes de actualizar TypeORM.
Buffer reemplazado por Uint8Array en plataformas que no son Node
Se ha eliminado el polyfill de Buffer para navegador. En plataformas que no son Node (navegador, Deno, Bun), los datos binarios ahora se representan como Uint8Array. Los usuarios de Node.js no se ven afectados — el Buffer de Node extiende Uint8Array y sigue funcionando como antes.
Cambios en los drivers
MySQL / MariaDB
Opción connectorPackage eliminada
La opción connectorPackage fue eliminada, junto con el soporte para el antiguo cliente mysql. El único cliente de base de datos admitido ahora es mysql2, que TypeORM cargará por defecto. Si usabas mysql en tu proyecto, simplemente sustitúyelo por mysql2.
Valor predeterminado de legacySpatialSupport cambiado a false
La opción legacySpatialSupport ahora tiene como valor predeterminado false, lo que significa que TypeORM usa las funciones espaciales compatibles con el estándar ST_GeomFromText y ST_AsText introducidas en MySQL 5.7 y requeridas por MySQL 8.0+. Las funciones heredadas GeomFromText y AsText fueron eliminadas en MySQL 8.0.
Si estás usando MySQL 5.6 o anterior y dependes de tipos espaciales, establece explícitamente legacySpatialSupport: true:
new DataSource({
type: "mysql",
legacySpatialSupport: true,
// ...
})
Opciones de columna width y zerofill eliminadas
MySQL 8.0.17 marcó como obsoleta la anchura de visualización para tipos enteros y el atributo ZEROFILL, y MySQL 8.4 las eliminó por completo. TypeORM ya no admite las opciones de columna width y zerofill. Si usabas estas opciones, elimínalas de tus definiciones de columnas:
// Before
@Column({ type: "int", width: 9, zerofill: true })
postCode: number
// After
@Column({ type: "int" })
postCode: number
Si necesitas formato de visualización con relleno de ceros, manéjalo en tu capa de aplicación usando String.prototype.padStart() o la función LPAD() de MySQL en una consulta en bruto. La opción unsigned para tipos enteros no se ve afectada por este cambio.
SQLite
El paquete sqlite3 ha sido descartado. Usa better-sqlite3 en su lugar:
// Before
new DataSource({
type: "sqlite",
database: "db.sqlite",
})
// After
new DataSource({
type: "better-sqlite3",
database: "db.sqlite",
})
Opción flags eliminada
El paquete sqlite3 aceptaba flags de apertura a nivel C (OPEN_URI, OPEN_SHAREDCACHE, etc.). better-sqlite3 no soporta esto — usa estas opciones dedicadas en su lugar:
-
readonlypara modo de solo lectura -
enableWALpara modo de journal WAL
Opción busyTimeout renombrada a timeout
El paquete sqlite3 usaba busyTimeout para configurar el tiempo de espera de ocupado de SQLite. better-sqlite3 usa timeout en su lugar (predeterminado: 5000ms):
// Before
new DataSource({
type: "sqlite",
database: "db.sqlite",
busyTimeout: 2000,
})
// After
new DataSource({
type: "better-sqlite3",
database: "db.sqlite",
timeout: 2000,
})
MongoDB
TypeORM ahora requiere el driver de Node.js mongodb v7 o superior (^7.0.0). Se eliminó el soporte para el driver mongodb v5/v6.
Opciones de conexión obsoletas eliminadas
Se eliminaron las siguientes opciones de conexión para MongoDB:
| Removed option | Action |
|---|---|
appname | Use appName (camelCase) instead |
fsync | Use writeConcern: { journal: true } instead |
j | Use writeConcern: { journal: true } instead |
keepAlive | Remove — always enabled since MongoDB Driver v6.0 |
keepAliveInitialDelay | Remove — not configurable since MongoDB Driver v6.0 |
ssl | Use tls instead |
sslCA | Use tlsCAFile instead |
sslCRL | Remove — no replacement in modern driver |
sslCert | Use tlsCertificateKeyFile instead |
sslKey | Use tlsCertificateKeyFile instead |
sslPass | Use tlsCertificateKeyFilePassword instead |
sslValidate | Use tlsAllowInvalidCertificates (inverted) instead |
useNewUrlParser | Remove — no-op since MongoDB Driver v4.0 |
useUnifiedTopology | Remove — no-op since MongoDB Driver v4.0 |
w | Use writeConcern: { w: 1 } instead |
wtimeout | Use writeConcern: { wtimeoutMS: 2500 } instead |
wtimeoutMS | Use writeConcern: { wtimeoutMS: 2500 } instead |
Método stats() eliminado
Se eliminó el método stats() de MongoQueryRunner, MongoEntityManager y MongoRepository. El comando subyacente collStats quedó obsoleto en MongoDB server 6.2 y el método Collection.stats() fue eliminado en MongoDB Driver v7.
Usa la etapa de agregación $collStats en su lugar. Ten en cuenta que la estructura de la respuesta es diferente: propiedades como count, size y storageSize están anidadas bajo storageStats en lugar de estar en el nivel superior.
// 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)
Globales getMongoRepository y getMongoManager eliminados
Se eliminaron las funciones globales obsoletas getMongoRepository() y getMongoManager(). Usa los métodos correspondientes en instancias de DataSource o EntityManager en su lugar:
// Before
import { getMongoManager, getMongoRepository } from "typeorm"
const manager = getMongoManager()
const repository = getMongoRepository(User)
// After
const manager = dataSource.mongoManager
const repository = dataSource.getMongoRepository(User)
Tipos
Los tipos internos de MongoDB (ObjectId, etc.) ya no se reexportan desde typeorm. Impórtalos directamente desde mongodb:
// Before
import { ObjectId } from "typeorm"
// After
import { ObjectId } from "mongodb"
MS SQL Server
Opción de conexión domain eliminada
La opción obsoleta domain en SqlServerConnectionCredentialsOptions ha sido eliminada. Usa la opción authentication con tipo NTLM en su lugar:
// 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
Se eliminaron varios alias obsoletos para conexiones SAP HANA.
-
hanaClientDriverfue eliminado. Usadriver. -
pool.maxfue eliminado. Usapool.maxConnectedOrPooled. -
pool.requestTimeoutfue eliminado. Usapool.maxWaitTimeoutIfPoolExhausted. -
pool.idleTimeoutfue eliminado. Usapool.maxPooledIdleTime(en segundos). -
pool.min,pool.maxWaitingRequestsypool.checkIntervalfueron eliminados sin reemplazo.
También ten en cuenta los cambios en el comportamiento predeterminado de la configuración del pool:
-
pool.maxPooledIdleTimeahora tiene como valor predeterminado30segundos y ya no recurre apool.idleTimeout. -
pool.maxWaitTimeoutIfPoolExhaustedahora tiene como valor predeterminado0y ya no recurre apool.requestTimeout.
Expo
Se ha eliminado el soporte para el driver SQLite heredado de Expo. La API heredada fue eliminada por Expo en el SDK v52. Actualiza a Expo SDK v52 o superior y usa la API asíncrona moderna de 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 (caché)
Se eliminó el soporte para clientes Redis heredados (v3) en RedisQueryResultCache. Actualiza a Redis client v4 o superior (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()
Data Source
Connection → DataSource
DataSource reemplazó a Connection en v0.3. El alias compatible con versiones anteriores ahora ha sido eliminado:
// 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()
Los siguientes cambios de nombre se aplican en todo:
| Before | After |
|---|---|
Connection | DataSource |
ConnectionOptions | DataSourceOptions |
BaseConnectionOptions | BaseDataSourceOptions |
MysqlConnectionOptions | MysqlDataSourceOptions |
| (same pattern for all drivers) | |
connection.connect() | dataSource.initialize() |
connection.close() | dataSource.destroy() |
connection.isConnected | dataSource.isInitialized |
Propiedad name eliminada
La propiedad obsoleta name en DataSource y BaseDataSourceOptions ha sido eliminada. Las conexiones nombradas se marcaron como obsoletas en v0.3 cuando se eliminó ConnectionManager. Si usabas name para identificar conexiones, gestiona tus instancias de DataSource directamente.
Nota: el código que lee dataSource.name ahora recibirá undefined en lugar de "default". Si usas este valor en registros o lógica multi-tenant, actualízalo en consecuencia.
La propiedad .connection en varias clases ahora es .dataSource
La propiedad connection en las clases Driver, QueryRunner, EntityManager, QueryBuilder, EntityMetadata y *Event se renombró a dataSource. Para EntityManager, este cambio se anunció en la versión 0.3, pero no se implementó realmente. Para facilitar la transición, se agregó un getter obsoleto que devuelve el mismo valor que dataSource.
Varios
La clase ConnectionManager ha sido eliminada. Si la usabas para gestionar múltiples conexiones, crea y gestiona tus instancias de DataSource directamente en su lugar.
ConnectionOptionsReader también ha sido simplificado: all() se renombró a get() (devuelve todas las configuraciones como arreglo), y los métodos antiguos get(name) y has(name) fueron eliminados.
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")
Funciones globales de conveniencia eliminadas
Las siguientes funciones globales obsoletas han sido eliminadas:
-
createConnection/createConnections -
getConnection -
getConnectionManager -
getConnectionOptions -
getManager -
getSqljsManager -
getRepository -
getTreeRepository -
createQueryBuilder
Usa los métodos equivalentes en tu instancia de DataSource:
// Before
const repo = getRepository(User)
const qb = createQueryBuilder("user")
// After
const repo = dataSource.getRepository(User)
const qb = dataSource.createQueryBuilder("user")
Eliminada la configuración mediante variables de entorno
La clase obsoleta ConnectionOptionsEnvReader y la capacidad de configurar conexiones mediante variables de entorno TYPEORM_CONNECTION, TYPEORM_URL y otras TYPEORM_* han sido eliminadas. El formato de archivo ormconfig.env tampoco es soportado. TypeORM ya no carga automáticamente archivos .env ni depende de dotenv.
Utiliza un archivo de configuración TypeScript o JavaScript en su lugar:
// ormconfig.ts
export default {
type: process.env.DB_TYPE,
url: process.env.DB_URL,
// ...
}
Cambios de comportamiento
Comportamiento predeterminado de invalidWhereValuesBehavior cambiado a throw
Este es un cambio de comportamiento significativo que podría romper aplicaciones existentes en tiempo de ejecución.
El comportamiento predeterminado para valores nulos e indefinidos en condiciones WHERE ha cambiado. Anteriormente, estos valores se ignoraban silenciosamente (la propiedad se omitía). Ahora, ambos lanzan un error por defecto.
Este cambio evita errores sutiles donde consultas como findBy({ id: undefined }) devolvían silenciosamente todas las filas en lugar de fallar.
// 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 } })
Para buscar valores nulos, usa el operador IsNull():
import { IsNull } from "typeorm"
await repository.find({ where: { text: IsNull() } })
Para restaurar el comportamiento anterior, configura invalidWhereValuesBehavior en las opciones de tu fuente de datos:
new DataSource({
// ...
invalidWhereValuesBehavior: {
null: "ignore",
undefined: "ignore",
},
})
Esta configuración protege todas las APIs de alto nivel — operaciones de búsqueda, métodos de mutación de repositorio/manager, y queryBuilder.setFindOptions() (el único método de QueryBuilder afectado). El resto de métodos de QueryBuilder (.where(), .andWhere(), .orWhere()) no están afectados — los valores nulos e indefinidos pasan directamente. Consulta Manejo de nulos e indefinidos para detalles completos.
Hashing
TypeORM usaba anteriormente el paquete npm sha.js para hashing SHA-1 (una implementación no estándar). Esto ha sido reemplazado por el módulo crypto integrado en Node.js, y el paquete uuid ha sido sustituido por crypto.randomUUID().
Para entornos de navegador, RandomGenerator.sha1 se corrigió para usar la implementación estándar.
Impacto: Si usas la caché de resultados de consultas de TypeORM, las entradas en caché existentes se invalidarán después de actualizar porque la función hash produce una salida diferente. Esto es inofensivo — las cachés se reconstruirán automáticamente — pero podrías ver un aumento temporal en fallos de caché.
Patrones glob
Los patrones glob (usados en la detección de archivos de entidades/migraciones) ahora son manejados por tinyglobby en lugar de glob. Esto es mayormente compatible, pero casos extremos con expansión de llaves o separadores de ruta específicos de plataforma pueden comportarse diferente.
Columnas
Eliminada la opción readonly
La opción obsoleta readonly para columnas ha sido eliminada. Usa la opción update en su lugar — ten en cuenta que toma el valor opuesto:
// Before
@Column({ readonly: true })
authorName: string
// After
@Column({ update: false })
authorName: string
Eliminado unsigned en ColumnNumericOptions
La propiedad obsoleta unsigned en ColumnNumericOptions (usada con sobrecargas de tipo decimal/float como @Column("decimal", { unsigned: true })) ha sido eliminada, ya que MySQL marcó como obsoleto UNSIGNED para tipos numéricos no enteros. La opción unsigned en ColumnOptions para tipos enteros no está afectada.
Relaciones
nullable: false ahora usa INNER JOIN
Las relaciones marcadas con nullable: false ahora usan INNER JOIN en lugar de LEFT JOIN cuando se cargan mediante relations, carga eager u opciones de búsqueda. Esto aplica solo para tipos de relaciones que poseen la columna de unión (ManyToOne y OneToOne del lado propietario).
Esto es semánticamente correcto porque una clave foránea no nula garantiza que la entidad relacionada existe, y permite al optimizador de la base de datos generar planes de consulta más eficientes.
Posible cambio disruptivo: Si tu base de datos contiene filas que violan la restricción NOT NULL (ej: claves foráneas huérfanas, o nullable: false estaba configurado pero la columna es realmente nullable en la BD), esas filas serán excluidas de los resultados. Verifica la integridad de tus datos o cambia la relación a nullable: true si es necesario.
// 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
Las relaciones OneToMany, ManyToMany e inversas OneToOne siempre usan LEFT JOIN independientemente de la configuración nullable, ya que estos tipos de relación no tienen una columna de unión en la tabla actual.
Excepción de soft-delete: Si la entidad relacionada tiene una @DeleteDateColumn, se usa LEFT JOIN incluso para relaciones nullable: false (a menos que se establezca withDeleted: true). Esto evita que entidades relacionadas eliminadas suavemente filtren sus filas padre.
Repositorio
findOneById
El método obsoleto findOneById ha sido eliminado de EntityManager, Repository, BaseEntity, MongoEntityManager y MongoRepository. Usa findOneBy en su lugar:
// 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 })
Para entidades MongoDB con @ObjectIdColumn(), findOneBy funciona igual: TypeORM traduce automáticamente el nombre de propiedad a _id.
Eliminado findByIds
El método obsoleto findByIds ha sido eliminado de EntityManager, Repository y BaseEntity. Usa findBy con el operador In en su lugar:
// 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 renombrado a exists
El método obsoleto Repository.exist() ha sido eliminado. Usa exists() en su lugar — el comportamiento es idéntico:
// Before
const hasUsers = await userRepository.exist({ where: { isActive: true } })
// After
const hasUsers = await userRepository.exists({ where: { isActive: true } })
Eliminados AbstractRepository, @EntityRepository y getCustomRepository
La clase AbstractRepository, el decorador @EntityRepository y el método getCustomRepository() han sido eliminados. Estas funcionalidades se marcaron como obsoletas en v0.3 en favor de 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 })
},
})
Las siguientes clases de error también fueron eliminadas: CustomRepositoryDoesNotHaveEntityError, CustomRepositoryCannotInheritRepositoryError, CustomRepositoryNotFoundError.
Eliminados el decorador @RelationCount y loadRelationCountAndMap
El decorador @RelationCount y el método SelectQueryBuilder.loadRelationCountAndMap() han sido eliminados. Usa @VirtualColumn o una subconsulta en tu constructor de consultas en su lugar:
// 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
Opciones de Búsqueda
Opción join eliminada
La propiedad obsoleta join en FindOneOptions y FindManyOptions ha sido eliminada, junto con la interfaz JoinOptions.
leftJoinAndSelect → relations
Si usabas leftJoinAndSelect, sustitúyelo con la sintaxis de objeto relations: relations siempre realiza LEFT JOINs con selección, lo cual es equivalente:
// 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 },
})
Otros tipos de join → QueryBuilder
La opción relations solo soporta LEFT JOINs con selección. Si usabas innerJoinAndSelect, innerJoin o leftJoin (sin select), cambia a la API de QueryBuilder:
// 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()
Esta distinción es importante en la práctica. Por ejemplo, PostgreSQL y CockroachDB no permiten FOR UPDATE en el lado nullable de un outer join, por lo que consultas que combinan bloqueo con relaciones unidas pueden requerir INNER JOINs:
// 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()
Bloqueo con relaciones anidadas → QueryBuilder
La opción relations no se puede usar con bloqueo pesimista en tablas unidas porque relations siempre utiliza LEFT JOINs, y PostgreSQL/CockroachDB rechazan FOR UPDATE en el lado anulable de las uniones externas. Usa QueryBuilder con innerJoinAndSelect en su lugar:
// 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()
Ten en cuenta que el bloqueo de la tabla principal aún funciona con relations — solo el bloqueo de tablas unidas requiere QueryBuilder con uniones internas.
select basado en cadenas eliminado
Se ha eliminado la sintaxis obsoleta de matriz de cadenas para las opciones de búsqueda select. Usa la sintaxis de objeto en su lugar:
// Before
const users = await repository.find({
select: ["id", "name"],
})
// After
const users = await repository.find({
select: { id: true, name: true },
})
El tipo eliminado es FindOptionsSelectByString.
relations basado en cadenas eliminado
Se ha eliminado la sintaxis obsoleta de matriz de cadenas para las opciones de búsqueda relations. Usa la sintaxis de objeto en su lugar:
// Before
const users = await repository.find({
relations: ["profile", "posts"],
})
// After
const users = await repository.find({
relations: { profile: true, posts: true },
})
El tipo eliminado es FindOptionsRelationByString.
QueryBuilder
printSql eliminado
Se eliminó el método printSql() de los query builders. Era redundante porque todas las consultas ejecutadas ya se registran automáticamente mediante el logger configurado cuando el registro de consultas está activado. Usa getSql() o getQueryAndParameters() para inspeccionar el SQL generado:
// 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()
Para registrar automáticamente todas las consultas ejecutadas, activa el registro de consultas en tu DataSource:
new DataSource({
// ...
logging: ["query"],
})
Eliminado onConflict
El método onConflict() en InsertQueryBuilder ha sido eliminado. Aceptaba cadenas SQL crudas que eran específicas del controlador y propensas a errores. Usa orIgnore() u orUpdate() en su lugar:
// 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()
Eliminada la sobrecarga de objeto en orUpdate
La sobrecarga basada en objetos orUpdate() que acepta { columns?, overwrite?, conflict_target? } ha sido eliminada. Utiliza la firma basada en arreglos en su lugar:
// Before
.orUpdate({ conflict_target: ["date"], overwrite: ["title"] })
// After
.orUpdate(["title"], ["date"])
Eliminado setNativeParameters
// Before
qb.setNativeParameters({ key: "value" })
// After
qb.setParameters({ key: "value" })
La propiedad interna QueryExpressionMap.nativeParameters también ha sido eliminada. Si tienes una subclase personalizada de QueryBuilder que accede a expressionMap.nativeParameters, cambia a expressionMap.parameters.
Eliminado el alias de tipo WhereExpression
// Before
import { WhereExpression } from "typeorm"
// After
import { WhereExpressionBuilder } from "typeorm"
Eliminado replacePropertyNames
El método protegido obsoleto replacePropertyNames() ha sido eliminado. Ya no tenía efecto desde que el reemplazo de nombres de propiedades se movió al procesamiento final de consultas mediante replacePropertyNamesForTheWholeQuery(). Si estabas sobrescribiendo este método en una subclase personalizada de QueryBuilder, tu sobrescritura ya no se invocará.
Eliminados modos de bloqueo obsoletos
// Before
.setLock("pessimistic_partial_write")
// After
.setLock("pessimistic_write")
.setOnLocked("skip_locked")
// Before
.setLock("pessimistic_write_or_fail")
// After
.setLock("pessimistic_write")
.setOnLocked("nowait")
Lo mismo aplica para opciones de búsqueda:
// 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" } }
Migraciones
Eliminado getAllMigrations
El método obsoleto getAllMigrations() ha sido eliminado de MigrationExecutor. Usa getPendingMigrations() o getExecutedMigrations() en su lugar, o accede directamente a dataSource.migrations para obtener la lista de clases de migración registradas:
// 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
Eliminados QueryRunner.loadedTables y loadedViews
// Before
const tables = queryRunner.loadedTables
const views = queryRunner.loadedViews
// After
const tables = await queryRunner.getTables()
const views = await queryRunner.getViews()
Nota: Los reemplazos son métodos asíncronos, no propiedades síncronas.
Sistema de contenedores
Se ha eliminado la integración obsoleta de contenedores IoC: useContainer(), getFromContainer(), ContainerInterface, ContainedType y UseContainerOptions.
TypeORM ya no tiene soporte integrado para contenedores IoC. Los paquetes typeorm-typedi-extensions y typeorm-routing-controllers-extensions tampoco son compatibles. Las siguientes secciones explican cómo migrar según tu configuración.
Suscriptores y migraciones con dependencias
TypeORM siempre instancia suscriptores y migraciones internamente usando un constructor sin argumentos, por lo que no puedes pasar instancias preconstruidas. Si tus migraciones necesitan acceder a servicios, usa el DataSource (disponible vía queryRunner.dataSource) dentro de la migración misma:
// 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)
// ...
}
}
Acceso a repositorios y al gestor de entidades
Si antes usabas typeorm-typedi-extensions para inyectar EntityManager o repositorios en tus servicios, usa el DataSource directamente en su lugar:
// 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)
}
}
Uso con un framework DI
Si usas un framework DI, registra el DataSource (o sus repositorios) como proveedores en tu contenedor:
// 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
Los usuarios de NestJS no están afectados — el paquete @nestjs/typeorm tiene su propia integración que no depende del sistema de contenedores eliminado en TypeORM. Sin embargo, @nestjs/typeorm v10 y la versión actual v11.0.0 intentan registrar la clase eliminada Connection y fallarán al iniciar. Asegúrate de usar una versión de @nestjs/typeorm que incluya la corrección para compatibilidad con TypeORM v1.
Otras eliminaciones internas
Se han eliminado las siguientes API internas. Esto solo te afectará si estabas construyendo drivers personalizados, extendiendo QueryBuilder o usando API de metadatos de bajo nivel:
| Removed | Replacement |
|---|---|
EntityMetadata.createPropertyPath() (static) | Removed with no public replacement |
DriverUtils.buildColumnAlias() | Use DriverUtils.buildAlias() |
Broadcaster.broadcastLoadEventsForAll() | No replacement — use individual event subscribers |
QueryExpressionMap.nativeParameters | Use QueryExpressionMap.parameters |