Separación de Definiciones de Entidades
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
Definición de Esquemas
Puedes definir una entidad y sus columnas directamente en el modelo usando decoradores. Pero algunos prefieren definir entidades y sus columnas en archivos separados, llamados "esquemas de entidad" en TypeORM.
Ejemplo de definición simple:
import { EntitySchema } from "typeorm"
export const CategoryEntity = new EntitySchema({
name: "category",
columns: {
id: {
type: Number,
primary: true,
generated: true,
},
name: {
type: String,
},
},
})
Ejemplo con relaciones:
import { EntitySchema } from "typeorm"
export const PostEntity = new EntitySchema({
name: "post",
columns: {
id: {
type: Number,
primary: true,
generated: true,
},
title: {
type: String,
},
text: {
type: String,
},
},
relations: {
categories: {
type: "many-to-many",
target: "category", // CategoryEntity
},
},
})
Ejemplo complejo:
import { EntitySchema } from "typeorm"
export const PersonSchema = new EntitySchema({
name: "person",
columns: {
id: {
primary: true,
type: "int",
generated: "increment",
},
firstName: {
type: String,
length: 30,
},
lastName: {
type: String,
length: 50,
nullable: false,
},
age: {
type: Number,
nullable: false,
},
countryCode: {
type: String,
length: 2,
foreignKey: {
target: "countries", // CountryEntity
inverseSide: "code",
},
},
cityId: {
type: Number,
foreignKey: {
target: "cities", // CityEntity
},
},
},
checks: [
{ expression: `"firstName" <> 'John' AND "lastName" <> 'Doe'` },
{ expression: `"age" > 18` },
],
indices: [
{
name: "IDX_TEST",
unique: true,
columns: ["firstName", "lastName"],
},
],
uniques: [
{
name: "UNIQUE_TEST",
columns: ["firstName", "lastName"],
},
],
foreignKeys: [
{
target: "cities", // CityEntity
columnNames: ["cityId", "countryCode"],
referencedColumnNames: ["id", "countryCode"],
},
],
})
Si deseas que tu entidad tenga tipos seguros, puedes definir un modelo y especificarlo en la definición del esquema:
import { EntitySchema } from "typeorm"
export interface Category {
id: number
name: string
}
export const CategoryEntity = new EntitySchema<Category>({
name: "category",
columns: {
id: {
type: Number,
primary: true,
generated: true,
},
name: {
type: String,
},
},
})
Extensión de Esquemas
Al usar el enfoque Decorator, es fácil extend columnas básicas a una clase abstracta y luego heredarlas.
Por ejemplo, tus columnas id, createdAt y updatedAt pueden definirse en una BaseEntity. Para más detalles, consulta
la documentación sobre herencia de tabla concreta.
Al usar el enfoque de EntitySchema, esto no es posible. Sin embargo, puedes aprovechar el Spread Operator (...).
Retomemos el ejemplo de Category anterior. Puedes querer extract descripciones de columnas básicas y reutilizarlas en
tus otros esquemas. Esto se puede hacer de la siguiente manera:
import { EntitySchemaColumnOptions } from "typeorm"
export const BaseColumnSchemaPart = {
id: {
type: Number,
primary: true,
generated: true,
} as EntitySchemaColumnOptions,
createdAt: {
name: "created_at",
type: "timestamp with time zone",
createDate: true,
} as EntitySchemaColumnOptions,
updatedAt: {
name: "updated_at",
type: "timestamp with time zone",
updateDate: true,
} as EntitySchemaColumnOptions,
}
Ahora puedes usar BaseColumnSchemaPart en tus otros modelos de esquema, así:
export const CategoryEntity = new EntitySchema<Category>({
name: "category",
columns: {
...BaseColumnSchemaPart,
// the CategoryEntity now has the defined id, createdAt, updatedAt columns!
// in addition, the following NEW fields are defined
name: {
type: String,
},
},
})
Puedes usar entidades embebidas en modelos de esquema, de esta forma:
export interface Name {
first: string
last: string
}
export const NameEntitySchema = new EntitySchema<Name>({
name: "name",
columns: {
first: {
type: "varchar",
},
last: {
type: "varchar",
},
},
})
export interface User {
id: string
name: Name
isActive: boolean
}
export const UserEntitySchema = new EntitySchema<User>({
name: "user",
columns: {
id: {
primary: true,
generated: "uuid",
type: "uuid",
},
isActive: {
type: "boolean",
},
},
embeddeds: {
name: {
schema: NameEntitySchema,
prefix: "name_",
},
},
})
Asegúrate de añadir también las columnas extended a la interfaz Category (por ejemplo, mediante export interface Category extend BaseEntity).
Herencia de Tabla Única
Para usar Herencia de Tabla Única:
-
Añade la opción
inheritanceal esquema de la clase padre, especificando el patrón de herencia ("STI") y la columna discriminadora, que almacenará el nombre de la clase hija en cada fila -
Configura la opción
type: "entity-child"en los esquemas de todas las clases hijas, extendiendo las columnas de la clase padre usando la sintaxis de spread operator descrita anteriormente
// entity.ts
export abstract class Base {
id!: number
type!: string
createdAt!: Date
updatedAt!: Date
}
export class A extends Base {
constructor(public a: boolean) {
super()
}
}
export class B extends Base {
constructor(public b: number) {
super()
}
}
export class C extends Base {
constructor(public c: string) {
super()
}
}
// schema.ts
const BaseSchema = new EntitySchema<Base>({
target: Base,
name: "Base",
columns: {
id: {
type: Number,
primary: true,
generated: "increment",
},
type: {
type: String,
},
createdAt: {
type: Date,
createDate: true,
},
updatedAt: {
type: Date,
updateDate: true,
},
},
// NEW: Inheritance options
inheritance: {
pattern: "STI",
column: "type",
},
})
const ASchema = new EntitySchema<A>({
target: A,
name: "A",
type: "entity-child",
// When saving instances of 'A', the "type" column will have the value
// specified on the 'discriminatorValue' property
discriminatorValue: "my-custom-discriminator-value-for-A",
columns: {
...BaseSchema.options.columns,
a: {
type: Boolean,
},
},
})
const BSchema = new EntitySchema<B>({
target: B,
name: "B",
type: "entity-child",
discriminatorValue: undefined, // Defaults to the class name (e.g. "B")
columns: {
...BaseSchema.options.columns,
b: {
type: Number,
},
},
})
const CSchema = new EntitySchema<C>({
target: C,
name: "C",
type: "entity-child",
discriminatorValue: "my-custom-discriminator-value-for-C",
columns: {
...BaseSchema.options.columns,
c: {
type: String,
},
},
})
Uso de Esquemas para Consultar/Insertar Datos
Por supuesto, puedes usar los esquemas definidos en tus repositorios o entity managers igual que usarías decoradores.
Considera el ejemplo de Category definido previamente (con su Interface y esquema CategoryEntity) para obtener
datos o manipular la base de datos.
// request data
const categoryRepository = dataSource.getRepository<Category>(CategoryEntity)
const category = await categoryRepository.findOneBy({
id: 1,
}) // category is properly typed!
// insert a new category into the database
const categoryDTO = {
// note that the ID is autogenerated; see the schema above
name: "new category",
}
const newCategory = await categoryRepository.save(categoryDTO)