Passa al contenuto principale

Multi-ORM Entities

How to define database entities in Ever Gauzy using the shared Multi-ORM decorator system for compatibility with both TypeORM and MikroORM.

Entity Definition Patternโ€‹

All entities use Multi-ORM decorators that generate metadata for both TypeORM and MikroORM:

import {
MultiORMEntity,
MultiORMColumn,
MultiORMManyToOne,
MultiORMOneToMany,
MultiORMManyToMany,
} from "@gauzy/core";
import { TenantOrganizationBaseEntity } from "@gauzy/core";

@MultiORMEntity("employee")
export class Employee extends TenantOrganizationBaseEntity {
// Simple columns
@MultiORMColumn()
firstName: string;

@MultiORMColumn()
lastName: string;

@MultiORMColumn({ nullable: true })
billRateValue?: number;

@MultiORMColumn({ nullable: true, type: "varchar" })
billRateCurrency?: string;

@MultiORMColumn({ nullable: true })
startedWorkOn?: Date;

@MultiORMColumn({ default: true })
isActive: boolean;

// Relations
@MultiORMManyToOne(() => User, { nullable: false, onDelete: "CASCADE" })
user: IUser;

@MultiORMColumn({ relationId: true })
userId: string;

@MultiORMOneToMany(() => TimeLog, (timeLog) => timeLog.employee)
timeLogs?: ITimeLog[];

@MultiORMManyToMany(() => OrganizationProject, (project) => project.members)
projects?: IOrganizationProject[];
}

Base Entity Classesโ€‹

Choosing the Right Base Classโ€‹

Base ClassFields ProvidedUse When
BaseEntityid, createdAt, updatedAt, isActive, isArchivedNon-tenant entities
TenantBaseEntity+ tenantId, tenantTenant-scoped, no organization
TenantOrganizationBaseEntity+ organizationId, organizationMost entities

BaseEntityโ€‹

export abstract class BaseEntity {
@MultiORMColumn({ primary: true })
id: string;

@MultiORMColumn({ createDate: true })
createdAt: Date;

@MultiORMColumn({ updateDate: true })
updatedAt: Date;

@MultiORMColumn({ nullable: true, default: true })
isActive?: boolean;

@MultiORMColumn({ nullable: true, default: false })
isArchived?: boolean;
}

TenantBaseEntityโ€‹

export abstract class TenantBaseEntity extends BaseEntity {
@MultiORMManyToOne(() => Tenant, { nullable: false })
tenant: ITenant;

@MultiORMColumn({ relationId: true })
tenantId: string;
}

TenantOrganizationBaseEntityโ€‹

export abstract class TenantOrganizationBaseEntity extends TenantBaseEntity {
@MultiORMManyToOne(() => Organization, { nullable: true })
organization?: IOrganization;

@MultiORMColumn({ relationId: true, nullable: true })
organizationId?: string;
}

Column Typesโ€‹

Basic Column Optionsโ€‹

// String
@MultiORMColumn()
name: string;

// Number
@MultiORMColumn({ type: 'numeric' })
amount: number;

// Boolean with default
@MultiORMColumn({ default: true })
isActive: boolean;

// Nullable
@MultiORMColumn({ nullable: true })
description?: string;

// Date
@MultiORMColumn({ nullable: true })
startDate?: Date;

// Enum
@MultiORMColumn({ type: 'varchar' })
status: StatusEnum;

// JSON/JSONB
@MultiORMColumn({ type: 'jsonb', nullable: true })
metadata?: Record<string, any>;

// Text (long content)
@MultiORMColumn({ type: 'text', nullable: true })
content?: string;

Relation Typesโ€‹

ManyToOneโ€‹

// Required relation
@MultiORMManyToOne(() => User, { nullable: false, onDelete: 'CASCADE' })
user: IUser;

@MultiORMColumn({ relationId: true })
userId: string;

// Optional relation
@MultiORMManyToOne(() => OrganizationProject, { nullable: true })
project?: IOrganizationProject;

@MultiORMColumn({ relationId: true, nullable: true })
projectId?: string;

OneToManyโ€‹

@MultiORMOneToMany(() => TimeLog, (timeLog) => timeLog.employee)
timeLogs?: ITimeLog[];

ManyToManyโ€‹

// With join table
@MultiORMManyToMany(() => Tag, (tag) => tag.employees)
@JoinTable({ name: 'tag_employee' })
tags?: ITag[];

// Without join table (inverse side)
@MultiORMManyToMany(() => OrganizationProject, (project) => project.members)
projects?: IOrganizationProject[];

OneToOneโ€‹

@MultiORMOneToOne(() => EmployeeSettings, (settings) => settings.employee)
settings?: IEmployeeSettings;

Contract Interfacesโ€‹

Every entity has a corresponding interface in @gauzy/contracts:

// packages/contracts/src/employee.model.ts
export interface IEmployee extends IBasePerTenantAndOrganizationEntityModel {
firstName: string;
lastName: string;
billRateValue?: number;
billRateCurrency?: string;
startedWorkOn?: Date;
isActive: boolean;
userId: string;
user?: IUser;
timeLogs?: ITimeLog[];
projects?: IOrganizationProject[];
}

The entity class implements the contract interface:

@MultiORMEntity("employee")
export class Employee
extends TenantOrganizationBaseEntity
implements IEmployee {
// ...
}

Best Practicesโ€‹

DOโ€‹

  • โœ… Always extend a BaseEntity subclass
  • โœ… Use MultiORM* decorators, not raw TypeORM/MikroORM decorators
  • โœ… Define a contract interface in @gauzy/contracts
  • โœ… Include relationId columns for all relations
  • โœ… Add nullable: true for optional fields

DON'Tโ€‹

  • โŒ Import decorators directly from typeorm or @mikro-orm/core
  • โŒ Use TypeORM-specific features like @Tree() without Multi-ORM support
  • โŒ Create entities without tenant scoping (unless intentionally cross-tenant)
  • โŒ Use enum column type directly (use varchar with TypeScript enum)