Skip to main content
Version: 6.2

Using Entity Constructors

Internally, MikroORM never calls entity constructor on managed entities (those loaded via EntityManager), so you are free to use it as you wish. The constructor will be called only when you instantiate the class yourself via new operator (or when using em.create() to create new entity instance), so it is a handy place to require your data when creating new entity.

For example following Book entity definition will always require to set title and author, but publisher will be optional:

@Entity()
export class Book {

@PrimaryKey()
id!: number;

@Property()
title: string;

@Property()
foo!: number;

@ManyToOne()
author: Author;

@ManyToOne()
publisher?: Publisher;

@ManyToMany({ entity: () => BookTag, inversedBy: 'books' })
tags = new Collection<BookTag>(this);

constructor(title: string, author: Author) {
this.title = title;
this.author = author;
}

}

Now you can construct your entity this way:

const author = new Author();
const book = new Book('Foo', author);

The constructor parameters will be automatically detected and respected by em.create() too:

const author = new Author();
const book = em.create(Book, { title: 'Foo', author, foo: 123 });

This will extract title and author from the data and pass it to the constructor, and assign only the rest (so here only the foo property) to the created entity.

Constructor parameter inference works based on the entity property names. In other words, your parameters need to be called exactly the same as entity properties.

POJO vs entity instance in constructor

It might be tempting to just define your constructor with a DTO as follows:

constructor(dto: { title: string; author: number }) {
this.title = dto.title;
// fails to compile, `number` is assignable not `Author`!
this.author = dto.author;
}

Similar (but more hidden) problem would appear if your dto.author was a POJO (so an object, but not an instance of the Author entity), as that might type check, although it won't work either. The ORM expects entity instances in relation properties, nothing else.

But worry not, since v5.6 there is an easy way to convert a primary key to the entity reference, the rel() helper:

@ManyToOne({ entity: () => Author })
author: Rel<Author>;

constructor(dto: { title: string; author: number }) {
this.title = dto.title;
this.author = rel(Author, dto.author);
}

The rel() helper will create entity instance that is not yet managed (as we don't pass it any EntityManager instance), but it will be considered as existing entity reference once it becomes managed. This is in fact an equivalent to em.getReference(), but without having the EntityManager instance at hand.

rel() is a shortcut for Reference.createNakedFromPK().

And if you want to be safer and use the Reference wrapper, the ref() helper also accepts this new signature:

@ManyToOne({ entity: () => Author, ref: true })
author: Ref<Author>;

constructor(dto: { title: string; author: number }) {
this.title = dto.title;
this.author = ref(Author, dto.author);
}

The rel and ref helpers will accept both primary key and entity instance, as well as empty value (null or undefined).

book.author = ref(Author, null);
book.author = ref(Author, undefined);
book.author = ref(null);
book.author = ref(undefined);
book.author = ref(Author, 1);
book.author = ref(Author, author);
book.author = ref(author);

Using native private properties

If you want to use native private properties inside entities, the default approach of how MikroORM creates entity instances via Object.create() is not viable (more about this in the issue). To force usage of entity constructors, you can use forceEntityConstructor toggle.