Skip to main content
Version: Next

Modeling Entity Relationships

There are 4 types of entity relationships in MikroORM:

  • ManyToOne
  • OneToMany
  • OneToOne
  • ManyToMany

Relations can be unidirectional and bidirectional. Unidirectional are defined only on one side (the owning side). Bidirectional are defined on both sides, while one is owning side (where references are store), marked by inversedBy attribute pointing to the inverse side. On the inversed side we define it with mappedBy attribute pointing back to the owner:

When modeling bidirectional relationship, you can also omit the inversedBy attribute, defining mappedBy on the inverse side is enough as it will be auto-wired.

ManyToOne

Many instances of the current Entity refer to One instance of the referred Entity.

There are multiple ways how to define the relationship, all of the following is equivalent:

@Entity()
export class Book {

@ManyToOne() // plain decorator is enough, type will be sniffer via reflection!
author1!: Author;

@ManyToOne(() => Author) // you can specify type manually as a callback
author2!: Author;

@ManyToOne('Author') // or as a string
author3!: Author;

@ManyToOne({ entity: () => Author }) // or use options object
author4!: Author;

}

You can also specify how operations on given entity should cascade to the referred entity.

OneToMany

One instance of the current Entity has Many instances (references) to the referred Entity.

Again, all of the following is equivalent:

@Entity()
export class Author {

@OneToMany(() => Book, book => book.author)
books1 = new Collection<Book>(this);

@OneToMany('Book', 'author')
books2 = new Collection<Book>(this);

@OneToMany({ mappedBy: book => book.author }) // referenced entity type can be sniffer too
books3 = new Collection<Book>(this);

@OneToMany({ entity: () => Book, mappedBy: 'author', orphanRemoval: true })
books4 = new Collection<Book>(this);

}

As you can see, OneToMany is the inverse side of ManyToOne (which is the owning side). More about how collections work can be found on collections page.

You can also specify how operations on given entity should cascade to the referred entities. There is also more aggressive remove mode called Orphan Removal (books4 example).

OneToOne

One instance of the current Entity refers to One instance of the referred Entity.

This is a variant of ManyToOne, where there is always just one entity on both sides. This means that the foreign key column is also unique.

Owning Side

@Entity()
export class User {

// when none of `owner/inverseBy/mappedBy` is provided, it will be considered owning side
@OneToOne()
bestFriend1!: User;

// side with `inversedBy` is the owning one, to define inverse side use `mappedBy`
@OneToOne({ inversedBy: 'bestFriend1' })
bestFriend2!: User;

// when defining it like this, you need to specifically mark the owning side with `owner: true`
@OneToOne(() => User, user => user.bestFriend2, { owner: true })
bestFriend3!: User;

}

Inverse Side

@Entity()
export class User {

@OneToOne({ mappedBy: 'bestFriend1', orphanRemoval: true })
bestFriend1!: User;

@OneToOne(() => User, user => user.bestFriend2, { orphanRemoval: true })
bestFriend2!: User;

}

As you can see, relationships can be also self-referencing (all of them. OneToOne also supports Orphan Removal).

ManyToMany

Many instances of the current Entity refers to Many instances of the referred Entity.

Here are examples of how you can define ManyToMany relationship:

Owning Side

@Entity()
export class Book {

// when none of `owner/inverseBy/mappedBy` is provided, it will be considered owning side
@ManyToMany()
tags1 = new Collection<BookTag>(this);

@ManyToMany(() => BookTag, 'books', { owner: true })
tags2 = new Collection<BookTag>(this);

@ManyToMany(() => BookTag, 'books', { owner: true })
tags3 = new Collection<BookTag>(this);

@ManyToMany(() => BookTag, 'books', { owner: true })
tags4 = new Collection<BookTag>(this);

// to define uni-directional many to many, simply provide only
@ManyToMany(() => Author)
friends: Collection<Author> = new Collection<Author>(this);

}

Inverse Side

@Entity()
export class BookTag {

// inverse side has to point to the owning side via `mappedBy` attribute/parameter
@ManyToMany(() => Book, book => book.tags)
books = new Collection<Book>(this);

}

Again, more information about how collections work can be found on collections page.

Relations in ESM projects

If you use ESM in your TypeScript project with reflect-metadata, you might fall into issues with circular dependencies, seeing errors like this:

ReferenceError: Cannot access 'Author' before initialization

To get around them, use the Rel mapped type. It is an identity type, which disables the problematic inference from reflect-metadata, that causes ESM projects to fail.

import { Rel } from '@mikro-orm/core';

@Entity()
export class Book {

@ManyToOne(() => Author)
author!: Rel<Author>;

}