MikroORM

Configuration

npm install @mikro-orm/cli \
@mikro-orm/entity-generator \
@mikro-orm/migrations \
@mikro-orm/core \
@mikro-orm/nestjs \
@mikro-orm/postgresql 
mikro-orm.config.ts
import { EntityGenerator } from '@mikro-orm/entity-generator';
import { Migrator } from '@mikro-orm/migrations';
import { defineConfig } from '@mikro-orm/postgresql';
import { SeedManager } from '@mikro-orm/seeder';
import dotenv from 'dotenv';

dotenv.config();

export default defineConfig({
  // for automatic entity loading and discovery
  // so that can create relationship between entites and set up database schema
  entities: ['./dist/src/entities/*.js', './dist/src/**/*.entity.js'],
  entitiesTs: ['./src/entities/*.ts', './src/**/*.entity.ts'],
  dbName: process.env.DATABASE_NAME,
  user: process.env.DATABASE_USER,
  password: process.env.DATABASE_PASSWORD,
  host: process.env.DATABASE_HOST,
  port: process.env.DATABASE_PORT
    ? parseInt(process.env.DATABASE_PORT, 10)
    : 5432,
  seeder: {
    path: './seeders', // path to the folder with seeders
    pathTs: undefined, // path to the folder with TS seeders (if used, you should put path to compiled files in `path`)
    defaultSeeder: 'DatabaseSeeder', // default seeder class name
    glob: '!(*.d).{js,ts}', // how to match seeder files (all .js and .ts files, but not .d.ts)
    emit: 'ts', // seeder generation mode
    fileName: (className: string) => className, // seeder file naming convention
  },
  // Install the add-on
  extensions: [EntityGenerator, Migrator, SeedManager],
  // allowGlobalContext: true,
});

NestJS Setting

  • Declare in root level

  • To define which repositories should be registered in the current scope you can use the forFeature() method.

Entity

  • Entities are simple javascript objects (so called POJO) without restrictions and without the need to extend base classes.

Entity Manager

  • The Entity Manager is a core component in MikroORM that handles all database operations and entity state management. Here's a comprehensive explanation:

    1. Core Responsibilities:

    2. Managing entity lifecycle

    3. Handling database transactions

    4. Persisting entities to the database

    5. Managing entity relationships

    6. Handling unit of work pattern

  • 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, we do not have to call persist on those, and flush is enough to update them.

  • To save entity state to database, we 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.

Repository

  • Entity Repositories are thin layers on top of EntityManager. They act as an extension point, so you can add custom methods, or even alter the existing ones. The default EntityRepository implementation just forwards the calls to underlying EntityManager instance.

Transaction

Unit of Work

  • MikroORM uses the Identity Map pattern to track objects. Whenever you fetch an object from the database, MikroORM will keep a reference to this object inside its UnitOfWork.

  • Only one SELECT query will be fired against the database here. In the second findOne() call MikroORM will check the identity map first and will skip the database round trip as it will find the entity already loaded.

  • "identity map" as a sort of "in memory cache"

  • It starts off empty, gets filled and updated as you perform calls with the entity manager, and items in it get pulled out of it when an operation matches an ID the identity map is aware of

  • It helps to reduce your application's memory footprint per request, by ensuring that even if you make multiple queries that match the same rows, those rows will only exist once in memory.

Migration

  • It allows you to generate migrations based on the current schema difference ( which is based on the entity discovery)

  • Migrations are classes that extend Migration abstract class:

  • To create first migration file

  • Here are the command list

Seeding

  • To initialize the data into table

Entity Generator

  • To generate entities from existing database schema

Schema-first vs Code-first

  • Code first: write the entity definitions first and then generate db schema by using migration

  • Schema first: write the schema definition first (or in the case of migrations, write the migrations first), execute it, and generate the entity definitions out of the database

Last updated

Was this helpful?