Zum Hauptinhalt springen

Entitäten

Inoffizielle Beta-Übersetzung

Diese Seite wurde von PageTurner AI übersetzt (Beta). Nicht offiziell vom Projekt unterstützt. Fehler gefunden? Problem melden →

Was ist eine Entität?

Eine Entität ist eine Klasse, die auf eine Datenbanktabelle (oder bei MongoDB auf eine Sammlung) abgebildet wird. Sie können eine Entität erstellen, indem Sie eine neue Klasse definieren und sie mit @Entity() markieren:

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

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

@Column()
firstName: string

@Column()
lastName: string

@Column()
isActive: boolean
}

Dadurch wird folgende Datenbanktabelle erstellt:

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

Grundlegende Entitäten bestehen aus Spalten und Beziehungen. Jede Entität MUSS eine Primärspalte haben (oder eine ObjectId-Spalte bei Verwendung von MongoDB).

Jede Entität muss in Ihren Data-Source-Optionen registriert werden:

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],
})

Alternativ können Sie das gesamte Verzeichnis mit allen Entitäten angeben – diese werden dann automatisch geladen:

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}"],
})

Falls Sie einen alternativen Tabellennamen für die User-Entität verwenden möchten, können Sie dies in @Entity angeben: @Entity("my_users"). Wenn Sie einen Basispräfix für alle Datenbanktabellen Ihrer Anwendung setzen möchten, können Sie entityPrefix in den Data-Source-Optionen festlegen.

Bei Verwendung eines Entitätskonstruktors müssen dessen Argumente optional sein. Da der ORM beim Laden aus der Datenbank Instanzen von Entitätsklassen erstellt, kennt er Ihre Konstruktorargumente nicht.

Weitere Informationen zu Parametern von @Entity finden Sie in der Dekoratoren-Referenz.

Entitätsspalten

Da Datenbanktabellen aus Spalten bestehen, müssen auch Ihre Entitäten Spalten enthalten. Jede Eigenschaft einer Entitätsklasse, die Sie mit @Column markieren, wird auf eine Spalte in der Datenbanktabelle abgebildet.

Primärspalten

Jede Entität muss mindestens eine Primärspalte haben. Es gibt verschiedene Arten von Primärspalten:

  • @PrimaryColumn() erstellt eine Primärspalte, die beliebige Werte jedes Typs akzeptiert. Sie können den Spaltentyp festlegen. Ohne Angabe wird der Typ automatisch vom Eigenschaftstyp abgeleitet. Im Beispiel unten entsteht eine id-Spalte vom Typ int, deren Wert Sie vor dem Speichern manuell zuweisen müssen.
import { Entity, PrimaryColumn } from "typeorm"

@Entity()
export class User {
@PrimaryColumn()
id: number
}
  • @PrimaryGeneratedColumn() erstellt eine Primärspalte, deren Wert automatisch durch Auto-Inkrement generiert wird. Es entsteht eine int-Spalte mit auto-increment/serial/sequence/identity (abhängig von Datenbank und Konfiguration). Sie müssen den Wert nicht manuell vor dem Speichern zuweisen – er wird automatisch generiert.
import { Entity, PrimaryGeneratedColumn } from "typeorm"

@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
}
  • @PrimaryGeneratedColumn("uuid") erstellt eine Primärspalte, deren Wert automatisch als uuid generiert wird. Uuid ist ein eindeutiger String-Identifier. Sie müssen den Wert nicht manuell zuweisen – er wird automatisch generiert.
import { Entity, PrimaryGeneratedColumn } from "typeorm"

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

Sie können auch zusammengesetzte Primärspalten verwenden:

import { Entity, PrimaryColumn } from "typeorm"

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

@PrimaryColumn()
lastName: string
}

Beim Speichern von Entitäten mit save wird stets versucht, eine Entität mit der angegebenen ID (oder IDs) in der Datenbank zu finden. Wenn die ID/IDs gefunden werden, wird die entsprechende Zeile aktualisiert. Wenn keine Zeile mit der ID/IDs existiert, wird eine neue Zeile eingefügt.

Um eine Entität anhand ihrer ID zu finden, können Sie manager.findOneBy oder repository.findOneBy verwenden. Beispiel:

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

Spezielle Spalten

Es stehen mehrere spezielle Spaltentypen mit Zusatzfunktionen zur Verfügung:

  • @CreateDateColumn ist eine spezielle Spalte, die automatisch auf das Erstellungsdatum der Entität gesetzt wird. Sie müssen diese Spalte nicht setzen – sie wird automatisch befüllt.

  • @UpdateDateColumn ist eine spezielle Spalte, die bei jedem Aufruf von save (Entity Manager/Repository) oder während upsert-Operationen bei Updates automatisch auf den Zeitpunkt der Aktualisierung gesetzt wird. Sie müssen diese Spalte nicht setzen – sie wird automatisch befüllt.

  • @DeleteDateColumn ist eine spezielle Spalte, die bei Soft-Delete-Operationen automatisch auf den Löschzeitpunkt gesetzt wird. Sie müssen diese Spalte nicht setzen – sie wird automatisch befüllt. Ist @DeleteDateColumn gesetzt, gilt standardmäßig der Scope "nicht gelöscht".

  • @VersionColumn ist eine spezielle Spalte, die bei jedem save-Aufruf oder während upsert-Updates automatisch auf die aktuelle Versionsnummer (fortlaufende Zahl) der Entität gesetzt wird. Sie müssen diese Spalte nicht setzen – sie wird automatisch befüllt.

Spaltentypen

TypeORM unterstützt alle gängigsten datenbankbasierten Spaltentypen. Spaltentypen sind datenbankspezifisch – dies ermöglicht mehr Flexibilität beim Design Ihres Datenbankschemas.

Sie können den Spaltentyp als ersten Parameter von @Column angeben oder in den Spaltenoptionen von @Column, zum Beispiel:

@Column("int")

oder

@Column({ type: "int" })

Wenn Sie zusätzliche Typparameter angeben möchten, können Sie dies über die Spaltenoptionen tun. Beispiel:

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

Hinweis zum Typ bigint: Der bigint-Spaltentyp in SQL-Datenbanken passt nicht in den regulären number-Typ und mappt die Eigenschaft stattdessen auf einen string.

enum-Spaltentyp

Der enum-Spaltentyp wird von postgres und mysql unterstützt. Es gibt verschiedene Definitionsmöglichkeiten:

Verwendung von TypeScript-Enums:

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
}

Hinweis: String-, numerische und heterogene Enums werden unterstützt.

Verwendung eines Arrays mit Enum-Werten:

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

@Entity()
export class User {

@PrimaryGeneratedColumn()
id: number;

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

simple-array-Spaltentyp

Es gibt einen speziellen Spaltentyp simple-array, der primitive Array-Werte in einer einzelnen String-Spalte speichert. Alle Werte sind durch Kommas getrennt. Beispiel:

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

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

Wird in einer einzelnen Datenbankspalte als Wert Alexander,Alex,Sasha,Shurik gespeichert. Beim Laden der Daten aus der Datenbank werden die Namen als Array zurückgegeben, genau wie sie gespeichert wurden.

Wichtig: Werte dürfen KEINE Kommas enthalten.

simple-json-Spaltentyp

Der spezielle Spaltentyp simple-json kann beliebige Werte speichern, die via JSON.stringify in der Datenbank gespeichert werden können. Besonders nützlich, wenn Ihr Datenbanksystem keinen JSON-Typ unterstützt und Sie Objekte ohne Aufwand speichern und laden möchten. Beispiel:

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

Wird in einer Datenbankspalte als {"name":"John","nickname":"Malkovich"} gespeichert. Beim Laden erhalten Sie Ihr Objekt/Array/Primitiv zurück via JSON.parse.

Spalten mit generierten Werten

Sie können Spalten mit generierten Werten über den Dekorator @Generated erstellen. Beispiel:

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

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

Der uuid-Wert wird automatisch generiert und in der Datenbank gespeichert.

Neben "uuid" gibt es die generierten Typen "increment", "identity" (nur Postgres 10+) und "rowid" (nur CockroachDB), allerdings gelten je nach Datenbankplattform Einschränkungen (z.B. erlauben manche Datenbanken nur eine Inkrement-Spalte oder benötigen sie als Primärschlüssel).

Vektor-Spalten

Vektorspalten werden in MariaDB/MySQL, Microsoft SQL Server, PostgreSQL (über die pgvector-Erweiterung) und SAP HANA Cloud unterstützt. Sie ermöglichen die Speicherung und Abfrage von Vektoreinbettungen für Ähnlichkeitssuchen und Machine-Learning-Anwendungen.

TypeORM unterstützt die Spaltentypen vector und halfvec datenbankübergreifend:

  • vector - Speichert Vektoren als 4-Byte-Floats (einfache Genauigkeit)

    • MariaDB/MySQL: Nativ vector-Typ
    • Microsoft SQL Server: Nativ vector-Typ
    • PostgreSQL: vector-Typ (via pgvector-Erweiterung)
    • SAP HANA Cloud: Alias für real_vector-Typ
  • halfvec - Speichert Vektoren als 2-Byte-Floats (halbe Genauigkeit) für speichereffiziente Darstellung

    • PostgreSQL: halfvec-Typ (via pgvector-Erweiterung)
    • SAP HANA Cloud: Alias für half_vector-Typ

Die Anzahl der Vektordimensionen können Sie mit der length-Option festlegen:

@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
}

Hinweis:

  • MariaDB/MySQL: Vektorunterstützung ab MariaDB 11.7 und MySQL 9
  • Microsoft SQL Server: Vektortypen erfordern SQL Server 2025 (17.x) oder neuer
  • PostgreSQL: Vektorspalten benötigen die pgvector-Erweiterung (stellt Vektortypen und Ähnlichkeitsoperatoren bereit)
  • SAP HANA: Vektorspalten erfordern SAP HANA Cloud (2024Q1+) und unterstützte @sap/hana-client-Version

Räumliche Spalten (Spatial Columns)

Microsoft SQLServer, MySQL/MariaDB, PostgreSQL/CockroachDB und SAP HANA unterstützen räumliche Spalten. TypeORMs Unterstützung variiert je nach Datenbank, insbesondere durch unterschiedliche Spaltennamen.

MS SQL, MySQL/MariaDB und SAP HANA verwenden Geometrien im Well-Known Text (WKT)-Format, daher sollten Geometriespalten als Typ string markiert werden.

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

Für Postgres/CockroachDB siehe PostGIS-Datentypen

Spaltenoptionen

Spaltenoptionen definieren zusätzliche Einstellungen für Ihre Entitätsspalten. Sie können sie in @Column angeben:

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

Liste verfügbarer Optionen in ColumnOptions:

  • type: ColumnType - Spaltentyp (einer der oben gelisteten Typen)

  • name: string - Spaltenname in der Datenbanktabelle. Standardmäßig wird der Name aus der Eigenschaft abgeleitet. Kann durch eigenen Namen überschrieben werden.

  • length: number - Länge des Spaltentyps (z.B. für varchar(150) Typangabe + Längenoption)

  • onUpdate: string - ON UPDATE-Trigger (nur in MySQL relevant)

  • nullable: boolean - Legt NULL/NOT NULL-Constraint fest. Standardwert ist nullable: false.

  • update: boolean - Gibt an, ob der Spaltenwert durch den "save"-Vorgang aktualisiert wird. Bei false kann der Wert nur beim ersten Einfügen des Objekts geschrieben werden. Standardwert ist true.

  • insert: boolean - Gibt an, ob der Spaltenwert beim ersten Einfügen des Objekts gesetzt wird. Standardwert ist true.

  • select: boolean - Legt fest, ob diese Spalte standardmäßig bei Abfragen ausgeblendet wird. Bei false werden die Spaltendaten nicht in einer Standardabfrage angezeigt. Standardmäßig ist select: true.

  • default: string - Fügt einen DEFAULT-Wert der Spalte auf Datenbankebene hinzu.

  • primary: boolean - Markiert die Spalte als Primärspalte. Entspricht der Verwendung von @PrimaryColumn.

  • unique: boolean - Markiert die Spalte als eindeutig (erstellt einen Unique-Constraint).

  • comment: string - Kommentar der Spalte in der Datenbank. Nicht von allen Datenbanktypen unterstützt.

  • precision: number - Die Genauigkeit für eine Dezimal-Spalte (exakte numerische Spalte, gilt nur für Dezimal-Spalten), also die maximale Anzahl der gespeicherten Ziffern. Wird bei einigen Spaltentypen verwendet.

  • scale: number - Die Skalierung für eine Dezimal-Spalte (exakte numerische Spalte, gilt nur für Dezimal-Spalten), die die Anzahl der Nachkommastellen angibt und nicht größer als die Genauigkeit sein darf. Wird bei einigen Spaltentypen verwendet.

  • unsigned: boolean - Setzt das UNSIGNED-Attribut auf eine numerische Spalte. Wird nur in MySQL verwendet.

  • charset: string - Definiert den Zeichensatz der Spalte. Nicht von allen Datenbanktypen unterstützt.

  • collation: string - Definiert die Sortierreihenfolge (Collation) der Spalte.

  • enum: string[]|AnyEnum - Wird beim enum-Spaltentyp verwendet, um die Liste der erlaubten Enum-Werte anzugeben. Sie können ein Array von Werten oder eine Enum-Klasse angeben.

  • enumName: string - Definiert den Namen für das verwendete Enum.

  • asExpression: string - Ausdruck für eine generierte Spalte. Wird nur in MySQL verwendet.

  • generatedType: "VIRTUAL"|"STORED" - Typ der generierten Spalte. Wird nur in MySQL verwendet.

  • hstoreType: "object"|"string" - Rückgabetyp der HSTORE-Spalte. Gibt den Wert als String oder Objekt zurück. Wird nur in Postgres verwendet.

  • array: boolean - Wird für Postgres- und CockroachDB-Spaltentypen verwendet, die ein Array sein können (z.B. int[]).

  • transformer: { from(value: DatabaseType): EntityType, to(value: EntityType): DatabaseType } - Wandelt Eigenschaften des Typs EntityType in einen datenbankkompatiblen Typ DatabaseType um. Arrays von Transformatoren werden unterstützt und beim Schreiben in natürlicher Reihenfolge angewendet, beim Lesen in umgekehrter Reihenfolge. Beispiel: [lowercase, encrypt] wandelt den String zuerst in Kleinbuchstaben um und verschlüsselt ihn beim Schreiben; beim Lesen wird entschlüsselt und dann nichts weiter gemacht.

  • utc: boolean - Gibt an, ob Datumswerte in UTC-Zeitzone statt der lokalen Zeitzone gespeichert und abgerufen werden sollen. Gilt nur für den Spaltentyp date. Standardwert ist false (verwendet lokale Zeitzone aus Gründen der Abwärtskompatibilität).

Hinweis: Die meisten dieser Spaltenoptionen sind RDBMS-spezifisch und in MongoDB nicht verfügbar.

Entitätsvererbung

Durch Entitätsvererbung können Sie Redundanzen in Ihrem Code reduzieren.

Beispielsweise haben Sie die Entitäten Photo, Question und 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
}

Alle diese Entitäten haben gemeinsame Spalten: id, title und description. Um Redundanzen zu reduzieren und eine bessere Abstraktion zu schaffen, können wir eine Basisklasse Content erstellen:

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
}

Alle Spalten (Relationen, Einbettungen etc.) von übergeordneten Entitäten (die Elternentität kann ebenfalls eine andere Entität erweitern) werden vererbt und in den finalen Entitäten erstellt.

Baumstrukturen in Entitäten

TypeORM unterstützt Adjazenzlisten- und Closure-Tabellen-Muster zur Speicherung von Baumstrukturen.

Adjazenzliste

Eine Adjazenzliste ist ein einfaches Modell mit Selbstreferenzierung.
Vorteil dieses Ansatzes ist die Einfachheit,
Nachteil ist die Unmöglichkeit, große Bäume auf einmal zu laden, bedingt durch JOIN-Beschränkungen.
Beispiel:

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

Eine Closure-Tabelle speichert Eltern-Kind-Beziehungen auf besondere Weise in einer separaten Tabelle.
Sie ist sowohl beim Lesen als auch Schreiben effizient.
Mehr zu Closure-Tabellen erfahren Sie in dieser hervorragenden Präsentation von Bill Karwin.
Beispiel:

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
}