Vai al contenuto principale

Entità

Traduzione Beta Non Ufficiale

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

Cos'è un'Entità?

Un'entità è una classe che mappa a una tabella del database (o a una collection quando si utilizza MongoDB). Puoi creare un'entità definendo una nuova classe e contrassegnandola con @Entity():

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number

@Column()
firstName: string

@Column()
lastName: string

@Column()
isActive: boolean
}

Questo creerà la seguente tabella nel database:

+-------------+--------------+----------------------------+
| user |
+-------------+--------------+----------------------------+
| id | int | PRIMARY KEY AUTO_INCREMENT |
| firstName | varchar(255) | |
| lastName | varchar(255) | |
| isActive | boolean | |
+-------------+--------------+----------------------------+

Le entità di base sono composte da colonne e relazioni. Ogni entità DEVE avere una colonna primaria (o una colonna ObjectId se si utilizza MongoDB).

Ogni entità deve essere registrata nelle opzioni della tua data source:

import { DataSource } from "typeorm"
import { User } from "./entities/User"

const myDataSource = new DataSource({
type: "mysql",
host: "localhost",
port: 3306,
username: "test",
password: "test",
database: "test",
entities: [User],
})

Oppure puoi specificare l'intera directory contenente tutte le entità - e tutte verranno caricate:

import { DataSource } from "typeorm"

const dataSource = new DataSource({
type: "mysql",
host: "localhost",
port: 3306,
username: "test",
password: "test",
database: "test",
entities: [__dirname + "/entities/**/*{.js,.ts}"],
})

Se desideri utilizzare un nome alternativo per la tabella dell'entità User, puoi specificarlo in @Entity: @Entity("my_users"). Se vuoi impostare un prefisso base per tutte le tabelle del database nella tua applicazione, puoi specificare entityPrefix nelle opzioni della data source.

Quando si utilizza un costruttore per un'entità, i suoi argomenti devono essere opzionali. Poiché l'ORM crea istanze delle classi entità durante il caricamento dal database, non conosce quindi i parametri del tuo costruttore.

Scopri di più sui parametri di @Entity nel riferimento ai decoratori.

Colonne delle entità

Poiché le tabelle del database sono composte da colonne, anche le tue entità devono esserlo. Ogni proprietà della classe entità contrassegnata con @Column verrà mappata a una colonna della tabella di database.

Colonne primarie

Ogni entità deve avere almeno una colonna primaria. Esistono diversi tipi di colonne primarie:

  • @PrimaryColumn() crea una colonna primaria che accetta qualsiasi valore di qualsiasi tipo. Puoi specificare il tipo di colonna. Se non specifichi un tipo, verrà dedotto dal tipo della proprietà. L'esempio seguente creerà un id di tipo int che dovrai assegnare manualmente prima del salvataggio.
import { Entity, PrimaryColumn } from "typeorm"

@Entity()
export class User {
@PrimaryColumn()
id: number
}
  • @PrimaryGeneratedColumn() crea una colonna primaria il cui valore viene generato automaticamente con un auto-incremento. Creerà una colonna int con auto-increment/serial/sequence/identity (dipende dal database e dalla configurazione). Non devi assegnare manualmente il valore prima del salvataggio: verrà generato automaticamente.
import { Entity, PrimaryGeneratedColumn } from "typeorm"

@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
}
  • @PrimaryGeneratedColumn("uuid") crea una colonna primaria il cui valore viene generato automaticamente come uuid. L'uuid è un identificatore stringa univoco. Non devi assegnare manualmente il valore prima del salvataggio: verrà generato automaticamente.
import { Entity, PrimaryGeneratedColumn } from "typeorm"

@Entity()
export class User {
@PrimaryGeneratedColumn("uuid")
id: string
}

Puoi avere anche colonne primarie composite:

import { Entity, PrimaryColumn } from "typeorm"

@Entity()
export class User {
@PrimaryColumn()
firstName: string

@PrimaryColumn()
lastName: string
}

Quando salvi entità usando save, il sistema cerca sempre un'entità nel database con l'id specificato (o gli id specificati). Se viene trovata una riga corrispondente all'id/ids, questa verrà aggiornata nel database. Se non esiste alcuna riga con l'id/ids specificato, verrà inserita una nuova riga.

Per trovare un'entità tramite id puoi usare manager.findOneBy o repository.findOneBy. Esempio:

// find one by id with single primary key
const person = await dataSource.manager.findOneBy(Person, { id: 1 })
const person = await dataSource.getRepository(Person).findOneBy({ id: 1 })

// find one by id with composite primary keys
const user = await dataSource.manager.findOneBy(User, {
firstName: "Timber",
lastName: "Saw",
})
const user = await dataSource.getRepository(User).findOneBy({
firstName: "Timber",
lastName: "Saw",
})

Colonne speciali

Sono disponibili diversi tipi di colonne speciali con funzionalità aggiuntive:

  • @CreateDateColumn è una colonna speciale impostata automaticamente alla data di inserimento dell'entità. Non devi impostare questa colonna: verrà assegnata automaticamente.

  • @UpdateDateColumn è una colonna speciale impostata automaticamente all'ora di aggiornamento dell'entità ogni volta che chiami save di entity manager o repository, o durante operazioni upsert quando avviene un aggiornamento. Non devi impostare questa colonna: verrà assegnata automaticamente.

  • @DeleteDateColumn è una colonna speciale impostata automaticamente all'ora di eliminazione dell'entità ogni volta che chiami il soft-delete di entity manager o repository. Non devi impostare questa colonna: verrà assegnata automaticamente. Se @DeleteDateColumn è impostata, lo scope predefinito sarà "non eliminato".

  • @VersionColumn è una colonna speciale impostata automaticamente alla versione dell'entità (numero incrementale) ogni volta che chiami save di entity manager o repository, o durante operazioni upsert quando avviene un aggiornamento. Non devi impostare questa colonna: verrà assegnata automaticamente.

Tipi di colonna

TypeORM supporta tutti i tipi di colonna più comunemente utilizzati e supportati dai database. I tipi di colonna sono specifici per il tipo di database - questo offre maggiore flessibilità sulla struttura dello schema del database.

Puoi specificare il tipo di colonna come primo parametro di @Column o nelle opzioni della colonna di @Column, ad esempio:

@Column("int")

oppure

@Column({ type: "int" })

Se vuoi specificare parametri aggiuntivi per il tipo, puoi farlo tramite le opzioni della colonna. Ad esempio:

@Column("varchar", { length: 200 })

Nota sul tipo bigint: il tipo di colonna bigint, usato nei database SQL, non rientra nel tipo number standard e invece mappa la proprietà a una string.

Tipo di colonna enum

Il tipo di colonna enum è supportato da postgres e mysql. Esistono varie definizioni possibili per le colonne:

Utilizzando enum TypeScript:

export enum UserRole {
ADMIN = "admin",
EDITOR = "editor",
GHOST = "ghost",
}

@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number

@Column({
type: "enum",
enum: UserRole,
default: UserRole.GHOST,
})
role: UserRole
}

Nota: Sono supportati enum di tipo stringa, numerici ed eterogenei.

Utilizzando un array con valori enum:

export type UserRoleType = "admin" | "editor" | "ghost",

@Entity()
export class User {

@PrimaryGeneratedColumn()
id: number;

@Column({
type: "enum",
enum: ["admin", "editor", "ghost"],
default: "ghost"
})
role: UserRoleType
}

Tipo di colonna simple-array

Esiste un tipo di colonna speciale chiamato simple-array che può memorizzare array di valori primitivi in una singola colonna stringa. Tutti i valori sono separati da una virgola. Ad esempio:

@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number

@Column("simple-array")
names: string[]
}
const user = new User()
user.names = ["Alexander", "Alex", "Sasha", "Shurik"]

Verrà memorizzato in una singola colonna del database come valore Alexander,Alex,Sasha,Shurik. Quando caricherai i dati dal database, i nomi verranno restituiti come un array di nomi, esattamente come li avevi memorizzati.

Nota: NON DEVI avere alcuna virgola nei valori che scrivi.

Tipo di colonna simple-json

Esiste un tipo di colonna speciale chiamato simple-json che può memorizzare qualsiasi valore archiviabile nel database tramite JSON.stringify. Molto utile quando non disponi del tipo JSON nel tuo database e vuoi memorizzare e caricare oggetti senza complicazioni. Ad esempio:

@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number

@Column("simple-json")
profile: { name: string; nickname: string }
}
const user = new User()
user.profile = { name: "John", nickname: "Malkovich" }

Verrà memorizzato in una singola colonna del database come valore {"name":"John","nickname":"Malkovich"}. Quando caricherai i dati dal database, otterrai nuovamente il tuo oggetto/array/primitive tramite JSON.parse.

Colonne con valori generati

Puoi creare colonne con valori generati usando il decoratore @Generated. Ad esempio:

@Entity()
export class User {
@PrimaryColumn()
id: number

@Column()
@Generated("uuid")
uuid: string
}

Il valore uuid verrà generato automaticamente e salvato nel database.

Oltre a "uuid", esistono anche i tipi generati "increment", "identity" (solo Postgres 10+) e "rowid" (solo CockroachDB), ma ci sono alcune limitazioni su alcune piattaforme database con questo tipo di generazione (ad esempio alcuni database consentono solo una colonna incrementale, o richiedono che l'incremento sia una chiave primaria).

Colonne vettoriali

Le colonne vettoriali sono supportate su MariaDB/MySQL, Microsoft SQL Server, PostgreSQL (tramite l'estensione pgvector) e SAP HANA Cloud, consentendo di memorizzare e interrogare gli embedding vettoriali per la ricerca di similarità e applicazioni di machine learning.

TypeORM supporta entrambi i tipi di colonna vector e halfvec su vari database:

  • vector - memorizza vettori come float a 4 byte (precisione singola)

    • MariaDB/MySQL: tipo nativo vector
    • Microsoft SQL Server: tipo nativo vector
    • PostgreSQL: tipo vector, disponibile tramite estensione pgvector
    • SAP HANA Cloud: alias per il tipo real_vector
  • halfvec - memorizza vettori come float a 2 byte (mezza precisione) per efficienza di memoria

    • PostgreSQL: tipo halfvec, disponibile tramite estensione pgvector
    • SAP HANA Cloud: alias per il tipo half_vector

Puoi specificare il numero di dimensioni del vettore utilizzando l'opzione length:

@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number

// Vector without specified dimensions
@Column("vector")
embedding: number[] | Buffer

// Vector with 3 dimensions: vector(3)
@Column("vector", { length: 3 })
embedding_3d: number[] | Buffer

// Half-precision vector with 4 dimensions: halfvec(4) (works on PostgreSQL and SAP HANA only)
@Column("halfvec", { length: 4 })
halfvec_embedding: number[] | Buffer
}

Nota:

  • MariaDB/MySQL: I vettori sono supportati da MariaDB 11.7 e MySQL 9
  • Microsoft SQL Server: Il supporto per il tipo vettoriale richiede SQL Server 2025 (17.x) o superiore.
  • PostgreSQL: Le colonne vettoriali richiedono l'installazione dell'estensione pgvector. L'estensione fornisce i tipi di dati vettoriali e gli operatori di similarità.
  • SAP HANA: Le colonne vettoriali richiedono SAP HANA Cloud (2024Q1+) e una versione supportata di @sap/hana-client.

Colonne spaziali

Microsoft SQLServer, MySQL/MariaDB, PostgreSQL/CockroachDB e SAP HANA supportano tutti colonne spaziali. Il supporto di TypeORM varia leggermente tra database, soprattutto perché i nomi delle colonne differiscono.

MS SQL, MySQL/MariaDB e SAP HANA utilizzano geometrie in formato well-known text (WKT), quindi le colonne di geometria dovrebbero essere etichettate con tipo string.

import { Entity, PrimaryColumn, Column } from "typeorm"

@Entity()
export class Thing {
@PrimaryColumn()
id: number

@Column("point")
point: string

@Column("linestring")
linestring: string
}

...

const thing = new Thing()
thing.point = "POINT(1 1)"
thing.linestring = "LINESTRING(0 0,1 1,2 2)"

Per Postgres/CockroachDB, consulta Tipi di dati Postgis

Opzioni delle colonne

Le opzioni delle colonne definiscono impostazioni aggiuntive per le colonne delle tue entità. Puoi specificare le opzioni su @Column:

@Column({
type: "varchar",
length: 150,
unique: true,
// ...
})
name: string;

Elenco delle opzioni disponibili in ColumnOptions:

  • type: ColumnType - Tipo di colonna. Uno dei tipi elencati sopra.

  • name: string - Nome della colonna nella tabella del database. Per impostazione predefinita, il nome della colonna è generato dal nome della proprietà. Puoi modificarlo specificando un nome personalizzato.

  • length: number - Lunghezza del tipo di colonna. Ad esempio, per creare un tipo varchar(150) specifichi tipo colonna e opzioni di lunghezza.

  • onUpdate: string - Trigger ON UPDATE. Utilizzato solo in MySQL.

  • nullable: boolean - Rende la colonna NULL o NOT NULL nel database. Per impostazione predefinita la colonna è nullable: false.

  • update: boolean - Indica se il valore della colonna viene aggiornato dall'operazione "save". Se false, sarà possibile scrivere questo valore solo durante il primo inserimento dell'oggetto. Valore predefinito: true.

  • insert: boolean - Indica se il valore della colonna viene impostato durante il primo inserimento dell'oggetto. Valore predefinito: true.

  • select: boolean - Definisce se nascondere questa colonna per impostazione predefinita nelle query. Se impostato su false, i dati della colonna non verranno mostrati in una query standard. Per impostazione predefinita è select: true.

  • default: string - Aggiunge il valore DEFAULT a livello di database per la colonna.

  • primary: boolean - Contrassegna la colonna come primaria. Equivale all'uso di @PrimaryColumn.

  • unique: boolean - Contrassegna la colonna come univoca (crea un vincolo di unicità).

  • comment: string - Commento della colonna nel database. Non supportato da tutti i tipi di database.

  • precision: number - Precisione per colonne decimali (numeriche esatte), rappresenta il numero massimo di cifre memorizzate. Si applica solo a colonne decimali. Utilizzato in alcuni tipi di colonna.

  • scale: number - Scala per colonne decimali (numeriche esatte), rappresenta il numero di cifre decimali a destra del punto. Deve essere minore o uguale alla precisione. Si applica solo a colonne decimali. Utilizzato in alcuni tipi di colonna.

  • unsigned: boolean - Applica l'attributo UNSIGNED alle colonne numeriche. Utilizzato solo in MySQL.

  • charset: string - Definisce il set di caratteri di una colonna. Non supportato da tutti i tipi di database.

  • collation: string - Definisce la collation di una colonna.

  • enum: string[]|AnyEnum - Utilizzato nel tipo di colonna enum per specificare l'elenco dei valori consentiti. Può essere un array di valori o una classe enum.

  • enumName: string - Definisce il nome per l'enum utilizzato.

  • asExpression: string - Espressione per colonne generate. Utilizzato solo in MySQL.

  • generatedType: "VIRTUAL"|"STORED" - Tipo di colonna generata. Utilizzato solo in MySQL.

  • hstoreType: "object"|"string" - Tipo di ritorno per colonne HSTORE. Restituisce il valore come stringa o oggetto. Utilizzato solo in Postgres.

  • array: boolean - Utilizzato per tipi di colonna Postgres e CockroachDB che supportano array (es. int[]).

  • transformer: { from(value: DatabaseType): EntityType, to(value: EntityType): DatabaseType } - Utilizzato per convertire proprietà di tipo arbitrario EntityType in tipo DatabaseType supportato dal database. Supporta array di transformer applicati in ordine naturale durante la scrittura e inverso durante la lettura. Es. [lowercase, encrypt] applica minuscole poi cripta in scrittura, decripta poi nulla in lettura.

  • utc: boolean - Indica se i valori di data devono essere memorizzati e recuperati in UTC anziché nel fuso orario locale. Si applica solo al tipo di colonna date. Valore predefinito: false (usa il fuso locale per compatibilità).

Nota: la maggior parte di queste opzioni sono specifiche per RDBMS e non disponibili in MongoDB.

Ereditarietà delle entità

Puoi ridurre la duplicazione del codice utilizzando l'ereditarietà tra entità.

Ad esempio, hai le entità Photo, Question, Post:

@Entity()
export class Photo {
@PrimaryGeneratedColumn()
id: number

@Column()
title: string

@Column()
description: string

@Column()
size: string
}

@Entity()
export class Question {
@PrimaryGeneratedColumn()
id: number

@Column()
title: string

@Column()
description: string

@Column()
answersCount: number
}

@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number

@Column()
title: string

@Column()
description: string

@Column()
viewCount: number
}

Come vedi, tutte queste entità condividono colonne comuni: id, title, description. Per ridurre la duplicazione e creare una migliore astrazione, possiamo definire una classe base Content:

export abstract class Content {
@PrimaryGeneratedColumn()
id: number

@Column()
title: string

@Column()
description: string
}
@Entity()
export class Photo extends Content {
@Column()
size: string
}

@Entity()
export class Question extends Content {
@Column()
answersCount: number
}

@Entity()
export class Post extends Content {
@Column()
viewCount: number
}

Tutte le colonne (relazioni, embed, ecc.) dalle entità genitore (un genitore può estendere anche altre entità) saranno ereditate e create nelle entità finali.

Entità ad albero

TypeORM supporta i modelli Adjacency list e Closure table per strutture ad albero.

Adjacency list

L'Adjacency list è un modello semplice con autoriferimento.
Vantaggio: semplicità implementativa.
Svantaggio: impossibilità di caricare alberi complessi in una singola query a causa di limitazioni nei JOIN.
Esempio:

import {
Entity,
Column,
PrimaryGeneratedColumn,
ManyToOne,
OneToMany,
} from "typeorm"

@Entity()
export class Category {
@PrimaryGeneratedColumn()
id: number

@Column()
name: string

@Column()
description: string

@ManyToOne((type) => Category, (category) => category.children)
parent: Category

@OneToMany((type) => Category, (category) => category.parent)
children: Category[]
}

Closure table

Una closure table memorizza le relazioni padre-figlio in una tabella separata con una struttura ottimizzata.
Efficiente sia in lettura che scrittura.
Per approfondimenti: presentazione di Bill Karwin.
Esempio:

import {
Entity,
Tree,
Column,
PrimaryGeneratedColumn,
TreeChildren,
TreeParent,
TreeLevelColumn,
} from "typeorm"

@Entity()
@Tree("closure-table")
export class Category {
@PrimaryGeneratedColumn()
id: number

@Column()
name: string

@Column()
description: string

@TreeChildren()
children: Category[]

@TreeParent()
parent: Category

@TreeLevelColumn()
level: number
}