There are 2 methods we should first describe to understand how persisting works in MikroORM:
em.persist(entity) is used to mark new entities for future persisting.
It will make the entity managed by given
EntityManager and once
flush will be called, it
will be written to the database.
flush, lets first define what managed entity is: An entity is managed if
it’s fetched from the database (via
em.findOne() or via other managed entity)
or registered as new through
em.flush() will go through all managed entities, compute appropriate change sets and
perform according database queries. As an entity loaded from database becomes managed
automatically, you do not have to call persist on those, and flush is enough to update
To save entity state to database, you need to persist it. Persist determines
whether to use
update and computes appropriate change-set. Entity references
that are not persisted yet (does not have identifier) will be cascade persisted automatically.
To fetch entities from database you can use
To populate entity relations, you can use
You can also use
em.populate() helper to populate relations (or to ensure they
are fully populated) on already loaded entities. This is also handy when loading
Conditions Object (
Querying entities via conditions object (
em.find(Entity, where: FilterQuery<T>))
supports many different ways:
As you can see in the fifth example, one can also use operators like
$re. More about that can be found in
Query Conditions section.
If you decide to abstract the filter options in your own object then you might run into the problem that the find option does not return the results you'd expect. This is due to the fact that the FilterQuery should be provided as a POJO (Plain Old JS Object
If you want to provide your own FilterQuery DTO, then your DTO class should extend the
PlainObject class. This way MikroORM knows it should be treated as such.
Type instantiation is excessively deep and possibly infinite.ts(2589) error#
Sometimes you might be facing TypeScript errors caused by too complex query for it to properly infer all types. Usually it can be solved by providing the type argument explicitly.
You can also opt in to use repository instead, as there the type inference should not be problematic.
As a last resort, you can always type cast the query to
Another problem you might be facing is
RangeError: Maximum call stack size exceeded error
thrown during TypeScript compilation (usually from file
The solution to this is the same, just provide the type argument explicitly.
You can also search by referenced entity properties. Simply pass nested where condition like this and all requested relationships will be automatically joined. Currently it will only join them so you can search and sort by those. To populate entities, do not forget to pass the populate parameter as well.
This feature is fully available only for SQL drivers. In MongoDB always you need to query from the owning side - so in the example above, first load book tag by name, then associated book, then the author. Another option is to denormalize the schema.
This feature is supported only for
When fetching single entity, you can choose to select only parts of an entity via
From v4.4 it is also possible to specify fields for nested relations:
Or with an alternative object syntax:
It is also possible to use multiple levels:
Primary keys are always selected even if you omit them. On the other hand, you are responsible
for selecting the FKs - if you omit such property, the relation might not be loaded properly.
In the following example the books would not be linked the author, because we did not specify
books.author field to be loaded.
Same problem can occur in mongo with M:N collections - those are stored as array property on the owning entity, so you need to make sure to mark such properties too.
If you are going to paginate your results, you can use
em.findAndCount() that will return
total count of entities before applying limit and offset.
When you call
em.findOne() and no entity is found based on your criteria,
null will be
returned. If you rather have an
Error instance thrown, you can use
You can customize the error either globally via
findOneOrFailHandler option, or locally via
failHandler option in
It is possible to use any SQL fragment in your
WHERE query or
ORDER BY clause:
expr()helper is an identity function - all it does is to return its parameter. We can use it to bypass the strict type checks in
This will produce following query:
Sometimes we might want to disable identity map and change set tracking for some query.
This is possible via
disableIdentityMap option. Behind the scenes, it will create new
context, load the entities inside that, and clear it afterwards, so the main identity map
will stay clean.
As opposed to managed entities, such entities are called detached. To be able to work with them, you first need to merge them via
Keep in mind that this can also have negative effect on the performance.
em.findOne() methods have generic return types.
All of following examples are equal and will let typescript correctly infer the entity type:
As the last one is the least verbose, it should be preferred.
Although you can use
EntityManager directly, much more convenient way is to use
EntityRepository instead. You can register
your repositories in dependency injection container like InversifyJS
so you do not need to get them from
EntityManager each time.