Trennung der Entitätsdefinition
Diese Seite wurde von PageTurner AI übersetzt (Beta). Nicht offiziell vom Projekt unterstützt. Fehler gefunden? Problem melden →
Definition von Schemata
Sie können eine Entität und ihre Spalten direkt im Modell mithilfe von Dekoratoren definieren. Manche bevorzugen jedoch, Entitäten und deren Spalten in separaten Dateien zu definieren, die in TypeORM als "Entity Schemata" bezeichnet werden.
Einfaches Definitionsbeispiel:
import { EntitySchema } from "typeorm"
export const CategoryEntity = new EntitySchema({
name: "category",
columns: {
id: {
type: Number,
primary: true,
generated: true,
},
name: {
type: String,
},
},
})
Beispiel mit Relationen:
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
},
},
})
Komplexes Beispiel:
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"],
},
],
})
Für typsichere Entitäten können Sie ein Modell definieren und es in der Schemadefinition angeben:
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,
},
},
})
Erweiterung von Schemata
Beim Decorator-Ansatz lassen sich Basis-Spalten einfach in eine abstrakte Klasse extend und erweitern.
Beispielsweise könnten Ihre id-, createdAt- und updatedAt-Spalten in einer solchen BaseEntity definiert werden. Details finden Sie
in der Dokumentation zur Konkrete Tabellenvererbung.
Beim EntitySchema-Ansatz ist dies nicht möglich. Allerdings können Sie den Spread Operator (...) nutzbringend einsetzen.
Nehmen wir das Category-Beispiel von oben: Sie könnten Basis-Spaltenbeschreibungen extract und in anderen Schemata wiederverwenden.
Dies lässt sich folgendermaßen umsetzen:
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,
}
Nun können Sie BaseColumnSchemaPart in anderen Schema-Modellen verwenden:
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,
},
},
})
Eingebettete Entitäten lassen sich in Schema-Modellen so nutzen:
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_",
},
},
})
Vergessen Sie nicht, die extended Spalten auch im Category-Interface hinzuzufügen (z.B. via export interface Category extend BaseEntity).
Einzeltabellenvererbung
So verwenden Sie Einzeltabellenvererbung:
-
Fügen Sie im Schema der Elternklasse die
inheritance-Option hinzu, die das Vererbungsmuster ("STI") und die Diskriminator-Spalte spezifiziert (sie speichert den Namen der Kindklasse pro Zeile) -
Setzen Sie für alle Kindklassen-Schemata die Option
type: "entity-child"und erweitern Sie die Spalten der Elternklasse mittels der oben beschriebenen Spread-Operator-Syntax
// 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,
},
},
})
Verwendung von Schemata für Datenabfragen/-einfügungen
Selbstverständlich können Sie definierte Schemata in Repositories oder dem Entity Manager genau wie Dekoratoren verwenden.
Nutzen Sie das zuvor definierte Category-Beispiel (mit seinem Interface und CategoryEntity-Schema) zum Abrufen
von Daten oder zur Manipulation der Datenbank.
// 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)