Vai al contenuto principale

Migrazione alla v1

Traduzione Beta Non Ufficiale

Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →

Questa è la guida alla migrazione per l'aggiornamento dalla versione 0.3.x alla 1.0.

Requisiti di piattaforma

Node.js 20+

Il target JavaScript minimo è ora ES2023, che richiede Node.js 20 o successivo. Se stai utilizzando una versione precedente di Node.js, effettua l'aggiornamento prima di aggiornare TypeORM.

Buffer sostituito con Uint8Array su piattaforme non Node

Il polyfill del browser Buffer è stato rimosso. Su piattaforme non Node (browser, Deno, Bun), i dati binari sono ora rappresentati come Uint8Array. Gli utenti Node.js non sono interessati — il Buffer di Node estende Uint8Array e continua a funzionare come prima.

Modifiche ai driver

MySQL / MariaDB

Opzione connectorPackage rimossa

L'opzione connectorPackage è stata rimossa, insieme al supporto per il vecchio client mysql. L'unico client database supportato ora è mysql2, che TypeORM tenterà di caricare per impostazione predefinita. Se stavi utilizzando mysql nel tuo progetto, sostituiscilo semplicemente con mysql2.

Comportamento predefinito di legacySpatialSupport cambiato in false

L'opzione legacySpatialSupport ora è predefinito false, il che significa che TypeORM utilizza le funzioni spaziali conformi allo standard ST_GeomFromText e ST_AsText introdotte in MySQL 5.7 e richieste da MySQL 8.0+. Le funzioni legacy GeomFromText e AsText sono state rimosse in MySQL 8.0.

Se stai utilizzando MySQL 5.6 o versioni precedenti e fai affidamento sui tipi spaziali, imposta esplicitamente legacySpatialSupport: true:

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

Opzioni di colonna width e zerofill rimosse

MySQL 8.0.17 ha deprecato la larghezza di visualizzazione per i tipi interi e l'attributo ZEROFILL, e MySQL 8.4 li ha rimossi completamente. TypeORM non supporta più le opzioni width e zerofill per le colonne. Se le stavi utilizzando, rimuovile dalle definizioni delle colonne:

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

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

Se hai bisogno di formattazione visuale con riempimento zero, gestiscila nel livello applicativo utilizzando String.prototype.padStart() o la funzione MySQL LPAD() in una query raw. L'opzione unsigned per i tipi interi non è interessata da questa modifica.

SQLite

Il pacchetto sqlite3 è stato abbandonato. Utilizza invece better-sqlite3:

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

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

Opzione flags rimossa

Il pacchetto sqlite3 accettava flag di apertura a livello C (OPEN_URI, OPEN_SHAREDCACHE, ecc.). better-sqlite3 non supporta questa funzionalità — utilizza invece le opzioni dedicate:

  • readonly per la modalità di sola lettura

  • enableWAL per la modalità journal WAL

Opzione busyTimeout rinominata in timeout

Il pacchetto sqlite3 utilizzava busyTimeout per configurare il timeout di occupato di SQLite. better-sqlite3 utilizza invece timeout (predefinito: 5000ms):

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

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

MongoDB

TypeORM ora richiede il driver Node.js mongodb v7 o successivo (^7.0.0). Il supporto per i driver mongodb v5/v6 è stato rimosso.

Opzioni di connessione deprecate rimosse

Sono state rimosse le seguenti opzioni di connessione 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

Metodo stats() rimosso

Il metodo stats() è stato rimosso da MongoQueryRunner, MongoEntityManager e MongoRepository. Il comando sottostante collStats è stato deprecato nel server MongoDB 6.2 e il metodo Collection.stats() è stato rimosso nel driver MongoDB v7.

Utilizza invece lo stadio di aggregazione $collStats. Nota che la struttura della risposta è diversa — proprietà come count, size e storageSize sono nidificate sotto storageStats invece che al livello principale.

// 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)

Funzioni globali getMongoRepository e getMongoManager rimosse

Le funzioni globali deprecate getMongoRepository() e getMongoManager() sono state rimosse. Utilizza invece i corrispondenti metodi delle istanze su DataSource o EntityManager:

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

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

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

Tipi

I tipi MongoDB interni (ObjectId, ecc.) non sono più riesportati da typeorm. Importali direttamente da mongodb:

// Before
import { ObjectId } from "typeorm"

// After
import { ObjectId } from "mongodb"

MS SQL Server

Opzione di connessione domain rimossa

L'opzione deprecata domain in SqlServerConnectionCredentialsOptions è stata rimossa. Utilizza invece l'opzione authentication con tipo 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

Sono stati rimossi diversi alias deprecati per le connessioni SAP HANA.

  • hanaClientDriver è stato rimosso. Utilizza driver.

  • pool.max è stato rimosso. Utilizza pool.maxConnectedOrPooled.

  • pool.requestTimeout è stato rimosso. Utilizza pool.maxWaitTimeoutIfPoolExhausted.

  • pool.idleTimeout è stato rimosso. Utilizza pool.maxPooledIdleTime (in secondi).

  • pool.min, pool.maxWaitingRequests e pool.checkInterval sono stati rimossi senza sostituti.

Nota anche i cambiamenti nel comportamento predefinito della configurazione del pool:

  • pool.maxPooledIdleTime ora è predefinito 30 secondi e non utilizza più fallback su pool.idleTimeout.

  • pool.maxWaitTimeoutIfPoolExhausted ora è predefinito 0 e non utilizza più fallback su pool.requestTimeout.

Expo

Il supporto per il driver SQLite legacy di Expo è stato rimosso. L'API legacy è stata rimossa da Expo nell'SDK v52. Aggiorna a Expo SDK v52 o successivo e utilizza la moderna API asincrona di 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 (cache)

Rimosso il supporto per i client Redis legacy (v3) in RedisQueryResultCache. Aggiorna a Redis client v4 o successivo (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

ConnectionDataSource

DataSource ha sostituito Connection nella v0.3. L'alias retrocompatibile è stato ora rimosso:

// 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()

Le seguenti ridenominazioni si applicano ovunque:

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

Proprietà name rimossa

La proprietà deprecata name su DataSource e BaseDataSourceOptions è stata rimossa. Le connessioni denominate sono state deprecate nella v0.3 quando ConnectionManager è stato rimosso. Se stavi utilizzando name per identificare le connessioni, gestisci invece direttamente le tue istanze di DataSource.

Nota: il codice che legge dataSource.name riceverà ora undefined invece di "default". Se utilizzi questo valore nella logica di logging o multi-tenant, aggiorna di conseguenza.

La proprietà .connection in varie classi ora è .dataSource

La proprietà connection nelle classi Driver, QueryRunner, EntityManager, QueryBuilder, EntityMetadata e *Event è stata rinominata in dataSource. Per EntityManager, questo cambiamento era stato annunciato nella versione 0.3, ma non era stato effettivamente implementato. Per facilitare la transizione, è stato aggiunto un getter deprecato che restituisce lo stesso valore di dataSource.

Varie

La classe ConnectionManager è stata rimossa. Se la utilizzavi per gestire connessioni multiple, crea e gestisci direttamente le tue istanze DataSource.

Anche ConnectionOptionsReader è stato semplificato: all() è stato rinominato in get() (restituisce tutte le configurazioni come array), mentre i vecchi metodi get(name) e has(name) sono stati rimossi.

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")

Funzioni globali di comodità rimosse

Le seguenti funzioni globali deprecate sono state rimosse:

  • createConnection / createConnections

  • getConnection

  • getConnectionManager

  • getConnectionOptions

  • getManager

  • getSqljsManager

  • getRepository

  • getTreeRepository

  • createQueryBuilder

Utilizza i metodi equivalenti sulla tua istanza DataSource:

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

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

Configurazione tramite variabili d'ambiente rimossa

La classe deprecata ConnectionOptionsEnvReader e la capacità di configurare connessioni tramite TYPEORM_CONNECTION, TYPEORM_URL e altre variabili d'ambiente TYPEORM_* sono state rimosse. Anche il formato file ormconfig.env non è più supportato. TypeORM non carica più automaticamente file .env né dipende da dotenv.

Utilizza invece un file di configurazione TypeScript o JavaScript:

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

Cambiamenti comportamentali

Comportamento predefinito di invalidWhereValuesBehavior cambiato in throw

Questo è un cambiamento comportamentale significativo che potrebbe interrompere le applicazioni esistenti in fase di runtime.

Il comportamento predefinito per i valori null e undefined nelle condizioni where è cambiato. Precedentemente, i valori null e undefined venivano ignorati silenziosamente (la proprietà veniva saltata). Ora, entrambi generano un errore per impostazione predefinita.

Questo cambiamento previene bug subdoli in cui query come findBy({ id: undefined }) restituivano silenziosamente tutte le righe invece di fallire.

// 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 } })

Per corrispondere ai valori null, utilizza l'operatore IsNull():

import { IsNull } from "typeorm"

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

Per ripristinare il comportamento precedente, imposta invalidWhereValuesBehavior nelle opzioni del tuo data source:

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

Questa impostazione protegge tutte le API di alto livello — operazioni di find, metodi di mutazione di repository/manager e queryBuilder.setFindOptions() (l'unico metodo di QueryBuilder interessato). Gli altri metodi di QueryBuilder (.where(), .andWhere(), .orWhere()) non sono interessati — i valori null e undefined passano così come sono. Vedi Gestione di null e undefined per i dettagli completi.

Hashing

TypeORM utilizzava in precedenza il pacchetto npm sha.js per l'hashing SHA-1 (un'implementazione non standard). Questo è stato sostituito con il modulo integrato crypto di Node.js, e il pacchetto uuid è stato sostituito con crypto.randomUUID().

Per gli ambienti browser, RandomGenerator.sha1 è stato corretto per utilizzare l'implementazione standard.

Impatto: Se utilizzi la cache dei risultati delle query di TypeORM, le voci esistenti nella cache saranno invalidate dopo l'aggiornamento perché la funzione di hash produce un output diverso. Questo è innocuo — le cache verranno ricostruite automaticamente — ma potresti vedere un breve aumento dei cache miss.

Pattern glob

I pattern glob (utilizzati per la scoperta dei file delle entità/migrazioni) sono ora gestiti da tinyglobby invece che da glob. Questa è sostanzialmente una sostituzione diretta, ma i casi limite con l'espansione delle parentesi graffe o i separatori di percorso specifici della piattaforma potrebbero comportarsi diversamente.

Colonne

Opzione readonly rimossa

L'opzione deprecata readonly per le colonne è stata rimossa. Utilizza invece l'opzione update — nota che accetta il valore opposto:

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

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

unsigned su ColumnNumericOptions rimosso

La proprietà deprecata unsigned su ColumnNumericOptions (utilizzata con gli overload del tipo colonna decimal/float come @Column("decimal", { unsigned: true })) è stata rimossa, poiché MySQL ha deprecato UNSIGNED per i tipi numerici non interi. L'opzione unsigned su ColumnOptions per i tipi interi non è interessata.

Relazioni

nullable: false ora usa INNER JOIN

Le relazioni contrassegnate con nullable: false ora utilizzano INNER JOIN invece di LEFT JOIN quando caricate tramite relations, eager loading o opzioni di ricerca. Si applica solo ai tipi di relazione che possiedono la colonna di join (ManyToOne e OneToOne lato proprietario).

Questo è semanticamente corretto poiché una chiave esterna non nullable garantisce l'esistenza dell'entità correlata e consente all'ottimizzatore del database di produrre piani di query più efficienti.

Potenziale breaking change: Se il tuo database contiene righe che violano il vincolo NOT NULL (es. chiavi esterne orfane o nullable: false impostato ma la colonna è effettivamente nullable nel DB), queste righe verranno escluse dai risultati. Verifica l'integrità dei dati o cambia la relazione in nullable: true se necessario.

// 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

Le relazioni OneToMany, ManyToMany e OneToOne inverse usano sempre LEFT JOIN indipendentemente dall'impostazione nullable, poiché questi tipi non hanno una colonna di join nella tabella corrente.

Eccezione per soft-delete: Se l'entità correlata ha una @DeleteDateColumn, viene usato LEFT JOIN anche per relazioni nullable: false (a meno che non sia impostato withDeleted: true). Questo previene che le entità correlate soft-deleted filtrino le righe genitore.

Repository

findOneById

Il metodo deprecato findOneById è stato rimosso da EntityManager, Repository, BaseEntity, MongoEntityManager e MongoRepository. Usa invece 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 })

Per entità MongoDB con @ObjectIdColumn(), findOneBy funziona allo stesso modo — TypeORM traduce automaticamente il nome della proprietà in _id.

findByIds rimosso

Il metodo deprecato findByIds è stato rimosso da EntityManager, Repository e BaseEntity. Utilizza invece findBy con l'operatore 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 rinominato in exists

Il metodo deprecato Repository.exist() è stato rimosso. Usa invece exists() — il comportamento è identico:

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

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

AbstractRepository, @EntityRepository e getCustomRepository rimossi

La classe AbstractRepository, il decoratore @EntityRepository e il metodo getCustomRepository() sono stati rimossi. Questi erano deprecati nella v0.3 a favore di 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 })
},
})

Sono state rimosse anche le seguenti classi di errore: CustomRepositoryDoesNotHaveEntityError, CustomRepositoryCannotInheritRepositoryError, CustomRepositoryNotFoundError.

Decoratore @RelationCount e loadRelationCountAndMap rimossi

Il decoratore @RelationCount e il metodo SelectQueryBuilder.loadRelationCountAndMap() sono stati rimossi. Utilizza invece @VirtualColumn o una sotto-query nel tuo query builder:

// 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

Opzioni di ricerca

Opzione join rimossa

La proprietà deprecata join su FindOneOptions e FindManyOptions è stata rimossa, insieme all'interfaccia JoinOptions.

leftJoinAndSelectrelations

Se usavi leftJoinAndSelect, sostituiscila con la sintassi object di relationsrelations esegue sempre LEFT JOIN con selezione, che è 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 },
})

Altri tipi di join → QueryBuilder

L'opzione relations supporta solo LEFT JOIN con selezione. Se usavi innerJoinAndSelect, innerJoin o leftJoin (senza select), passa all'API 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()

Questa distinzione è rilevante nella pratica. Ad esempio, PostgreSQL e CockroachDB non consentono FOR UPDATE sul lato nullable di un outer join, quindi le query che combinano locking con relazioni join potrebbero richiedere 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()

Locking con relazioni annidate → QueryBuilder

L'opzione relations non può essere utilizzata con il pessimistic locking su tabelle unite perché relations utilizza sempre LEFT JOIN, e PostgreSQL/CockroachDB rifiutano FOR UPDATE sul lato nullable degli outer join. Utilizza invece QueryBuilder con 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()

Nota che il blocco della tabella principale funziona ancora con relations — solo il blocco delle tabelle unite richiede QueryBuilder con inner join.

Rimozione di select basato su stringhe

La sintassi deprecata con array di stringhe per le opzioni select è stata rimossa. Utilizza invece la sintassi ad oggetto:

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

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

Il tipo rimosso è FindOptionsSelectByString.

Rimozione di relations basato su stringhe

La sintassi deprecata con array di stringhe per le opzioni relations è stata rimossa. Utilizza invece la sintassi ad oggetto:

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

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

Il tipo rimosso è FindOptionsRelationByString.

QueryBuilder

printSql rimosso

Il metodo printSql() nei query builder è stato rimosso. Era ridondante perché tutte le query eseguite vengono già automaticamente registrate tramite il logger configurato quando la registrazione delle query è abilitata. Utilizza getSql() o getQueryAndParameters() per ispezionare la SQL generata:

// 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()

Per registrare automaticamente tutte le query eseguite, abilita la registrazione delle query nel tuo DataSource:

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

onConflict rimosso

Il metodo onConflict() su InsertQueryBuilder è stato rimosso. Accettava stringhe SQL raw che erano specifiche del driver e soggette a errori. Utilizza invece orIgnore() o 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()

Overload dell'oggetto orUpdate rimosso

L'overload basato su oggetti di orUpdate() che accettava { columns?, overwrite?, conflict_target? } è stato rimosso. Utilizza invece la firma basata su array:

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

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

setNativeParameters rimosso

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

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

La proprietà interna QueryExpressionMap.nativeParameters è stata anch'essa rimossa. Se hai una sottoclasse personalizzata di QueryBuilder che accede a expressionMap.nativeParameters, passa a expressionMap.parameters.

Alias di tipo WhereExpression rimosso

// Before
import { WhereExpression } from "typeorm"

// After
import { WhereExpressionBuilder } from "typeorm"

replacePropertyNames rimosso

Il metodo protetto deprecato replacePropertyNames() è stato rimosso. Era diventato un'operazione nulla (no-op) poiché la sostituzione dei nomi delle proprietà è stata spostata nell'elaborazione di fine query tramite replacePropertyNamesForTheWholeQuery(). Se stavi sovrascrivendo questo metodo in una sottoclasse personalizzata di QueryBuilder, la sovrascrittura non viene più chiamata.

Modalità di lock deprecate rimosse

// 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 stesso vale per le opzioni di ricerca:

// 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" } }

Migrazioni

getAllMigrations rimosso

Il metodo deprecato getAllMigrations() è stato rimosso da MigrationExecutor. Utilizza invece getPendingMigrations() o getExecutedMigrations(), oppure accedi direttamente a dataSource.migrations per la lista delle classi di migrazione registrate:

// 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 e loadedViews rimossi

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

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

Nota: le sostituzioni sono metodi asincroni, non proprietà sincrone.

Sistema di container

L'integrazione deprecata del container IoC è stata rimossa: useContainer(), getFromContainer(), ContainerInterface, ContainedType e UseContainerOptions.

TypeORM non include più il supporto integrato per il container IoC. I pacchetti typeorm-typedi-extensions e typeorm-routing-controllers-extensions non sono più compatibili. Le sezioni seguenti spiegano come migrare in base alla tua configurazione.

Sottoscrittori e migrazioni con dipendenze

TypeORM istanzia sempre internamente i subscriber e le migration utilizzando un costruttore senza argomenti, quindi non è possibile passare istanze pre-costruite. Se le tue migration necessitano di accedere a servizi, utilizza il DataSource (disponibile tramite queryRunner.dataSource) all'interno della migration stessa:

// 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)
// ...
}
}

Accesso ai repository e all'entity manager

Se in precedenza utilizzavi typeorm-typedi-extensions per iniettare EntityManager o repository nei tuoi servizi, utilizza invece direttamente il 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)
}
}

Utilizzo con un framework DI

Se utilizzi un framework DI, registra il DataSource (o i suoi repository) come provider nel tuo container:

// 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

Gli utenti di NestJS non sono interessati — il pacchetto @nestjs/typeorm ha la propria integrazione che non dipende dal sistema di container rimosso da TypeORM. Tuttavia, @nestjs/typeorm v10 e l'attuale v11.0.0 tentano di registrare la classe Connection rimossa e causeranno un crash all'avvio. Assicurati di utilizzare una versione di @nestjs/typeorm che includa la correzione per la compatibilità con TypeORM v1.

Altre rimozioni interne

Le seguenti API interne sono state rimosse. Queste modifiche ti riguardano solo se stavi sviluppando driver personalizzati, estendendo QueryBuilder o utilizzando API di metadati di basso livello:

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