Working with Entity Manager
#
Persist and FlushThere are 2 methods we should first describe to understand how persisting works in MikroORM:
em.persist()
and em.flush()
.
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.
To understand flush
, lets first define what managed entity is: An entity is managed if
it’s fetched from the database (via em.find()
, em.findOne()
or via other managed entity)
or registered as new through em.persist()
.
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
them.
#
Persisting and CascadingTo save entity state to database, you need to persist it. Persist determines
whether to use insert
or update
and computes appropriate change-set. Entity references
that are not persisted yet (does not have identifier) will be cascade persisted automatically.
#
Fetching Entities with EntityManagerTo fetch entities from database you can use find()
and findOne()
of EntityManager
:
Example:
To populate entity relations, you can use populate
parameter.
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
entities via QueryBuilder
:
FilterQuery<T>
)#
Conditions Object (Querying entities via conditions object (where
in em.find(Entity, where: FilterQuery<T>)
)
supports many different ways:
As you can see in the fifth example, one can also use operators like $and
, $or
, $gte
,
$gt
, $lte
, $lt
, $in
, $nin
, $eq
, $ne
, $like
, $re
. More about that can be found in
Query Conditions section.
Type instantiation is excessively deep and possibly infinite.ts(2589)
error#
Mitigating 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
any
.
Another problem you might be facing is RangeError: Maximum call stack size exceeded
error
thrown during TypeScript compilation (usually from file node_modules/typescript/lib/typescript.js
).
The solution to this is the same, just provide the type argument explicitly.
#
Searching by referenced entity fieldsYou 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.
#
Fetching Partial EntitiesThis feature is supported only for
SELECT_IN
loading strategy.
When fetching single entity, you can choose to select only parts of an entity via options.fields
:
#
Fetching Paginated ResultsIf you are going to paginate your results, you can use em.findAndCount()
that will return
total count of entities before applying limit and offset.
#
Handling Not Found EntitiesWhen 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 em.findOneOrFail()
:
You can customize the error either globally via findOneOrFailHandler
option, or locally via
failHandler
option in findOneOrFail
call.
#
Using custom SQL fragmentsIt is possible to use any SQL fragment in your WHERE
query or ORDER BY
clause:
The
expr()
helper is an identity function - all it does is to return its parameter. We can use it to bypass the strict type checks inFilterQuery
.
This will produce following query:
#
Type of Fetched EntitiesBoth em.find
and 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.
#
Entity RepositoriesAlthough 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.
For more examples, take a look at
tests/EntityManager.mongo.test.ts
or tests/EntityManager.mysql.test.ts
.