Aller au contenu principal
Version: 3.0.0

MikroORM

This section describes how users use MikroORM in midway. MikroORM is the TypeScript ORM of Node.js based on data mapper, working unit and identity mapping mode.

The MikroORM official website document is here.

Related information:

Description
Can be used for standard projects
Can be used for Serverless
Can be used for integration
Contains independent main framework
Contains independent logs

About upgrade

  • Starting from the v3.14.0 version of the component, mikro v5/v6 versions are supported. Since there are major changes from mikro v5 to v6, if you want to upgrade from an old version of mikro, please read [Upgrading from v5 to v6](https:/ /mikro-orm.io/docs/upgrading-v5-to-v6)
  • Component examples updated to v6

Installation Components

Install mikro components to provide access to mikro-orm.

$ npm i @midwayjs/mikro@3 @mikro-orm/core --save

Or reinstall the following dependencies in package.json.

{
"dependencies": {
"@midwayjs/mikro": "^3.0.0",
"@mikro-orm/core": "^6.0.2",
// ...
},
"devDependencies": {
// ...
}
}

At the same time, it is also necessary to introduce the adaptation package of the corresponding database.

For example:

{
"dependencies": {
// sqlite
"@mikro-orm/sqlite": "^6.0.2",

// mysql
"@mikro-orm/mysql": "^6.0.2",
},
"devDependencies": {
// ...
}
}

For more information about drivers, see Official documentation.

Introducing components

The mikro component is introduced in src/configuration.ts, as an example.

// configuration.ts
import { Configuration } from '@midwayjs/core';
import * as mikro from '@midwayjs/mikro';
import { join } from 'path';

@Configuration({
imports: [
// ...
Mikro // load mikro components
],
importConfigs: [
join(__dirname, './config')
]
})
export class MainConfiguration {

}

Basic use

Similar to other orm frameworks, they are divided into several steps:

    1. Define Entity
    1. Configure the data source
    1. Get the EntityModel to call

For more information about Entity code, see Example.

Define Entity

Entity that defines the basis.

// src/entity/BaseEntity.ts
import { PrimaryKey, Property } from '@mikro-orm/core';

export abstract class BaseEntity {

@PrimaryKey()
id! : number;

@Property()
createdAt: Date = new Date();

@Property({ onUpdate: () => new Date() })
updatedAt: Date = new Date();

}

Define the actual Entity, including one-to-many, many-to-many relationships.

import { Cascade, Collection, Entity, ManyToMany, ManyToOne, Property } from '@mikro-orm/core';
import { Author, BookTag, Publisher } from './index';
import { BaseEntity } from './BaseEntity';

@Entity()
export class Book extends BaseEntity {

@Property()
title: string;

@ManyToOne(() => Author)
author: Author;

@ManyToOne(() => Publisher, { cascade: [Cascade.PERSIST, Cascade.REMOVE], nullable: true })
publisher?: Publisher;

@ManyToMany(() => BookTag)
tags = new Collection<BookTag>(this);

@Property({ nullable: true })
metaObject?: object;

@Property({ nullable: true })
metaArray?: any[];

@Property({ nullable: true })
metaArrayOfStrings?: string[];

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

}

Configure the data source

mikro v5 and v6 are slightly different.

// src/config/config.default
import { Author, BaseEntity, Book, BookTag, Publisher } from '../entity';
import { join } from 'path';
import { SqliteDriver } from '@mikro-orm/sqlite';

export default (appInfo) => {
return {
mikro: {
dataSource: {
default: {
entities: [Author, Book, BookTag, Publisher, BaseEntity],
dbName: join(__dirname, '../../test.sqlite'),
driver: SqliteDriver, // SQLite is used as an example here.
allowGlobalContext: true,
}
}
}
}
}

For association in the form of a directory scan, please refer to Data Source Management.

CRUD Operations

Use InjectRepository to inject Repository to perform simple query operations. And use InjectEntityManager to get the instance of EntityManager, to perform creating, updating and deleting operations. You can also get EntityManager by calling repository.getEntityManger().

attention
    1. Since v5.7, persist and flush etc. on Repository (shortcuts to methods on EntityManager) were marked as deprecated, and planned to remove them in v6. Please use those APIs on EntityManger directly instead of on Repository.
    1. v6 has been completely deprecated the above interface
import { Book } from './entity';
import { Provide } from '@midwayjs/core';
import { InjectEntityManager, InjectRepository } from '@midwayjs/mikro';
import { QueryOrder } from '@mikro-orm/core';
import { EntityManager, EntityRepository } from '@mikro-orm/mysql'; // should be imported from driver specific packages

@Provide()
export class BookService {

@InjectRepository(Book)
bookRepository: EntityRepository<Book>;

@InjectEntityManager()
em: EntityManager;

async queryByRepo() {
// query with Repository
const books = await this.bookRepository.findAll({
populate: ['author'],
orderBy: { title: QueryOrder.DESC },
limit: 20,
});
return books;
}

async createBook() {
const book = new Book({ title: 'b1', author: { name: 'a1', email: 'e1' } });
// mark book as persisted
this.em.persist(book);
// persist all changes to database
await this.em.flush();
return book;
}
}

Advanced Features

Get data source

The data source is the created data source object, which we can obtain by injecting the built-in data source manager.

import { Configuration } from '@midwayjs/core';
import { MikroDataSourceManager } from '@midwayjs/mikro';

@Configuration({
//...
})
export class MainConfiguration {

async onReady(container: IMidwayContainer) {
const dataSourceManager = await container. getAsync(MikroDataSourceManager);
const orm = dataSourceManager.getDataSource('default');
const connection = orm.em.getConnection();
//...
}
}

Starting with v3.8.0, it is also possible to inject via a decorator.

import { Configuration } from '@midwayjs/core';
import { InjectDataSource } from '@midwayjs/mikro';
import { MikroORM, IDatabaseDriver, Connection } from '@mikro-orm/core';

@Configuration({
//...
})
export class MainConfiguration {

// Inject the default data source
@InjectDataSource()
defaultDataSource: MikroORM<IDatabaseDriver<Connection>>;

// inject custom data source
@InjectDataSource('default1')
customDataSource: MikroORM<IDatabaseDriver<Connection>>;

async onReady(container: IMidwayContainer) {
//...
}
}

Logging

Midway's logger can be added to mikro through configuration to record SQL and other information.

// src/config/config.default.ts
exporg default {
midwayLogger: {
clients: {
mikroLogger: {
// ...
}
}
},
mikro: {
dataSource: {
default: {
entities: [Author, Book, BookTag, Publisher, BaseEntity],
// ...
logger: 'mikroLogger',
}
},
}
}

By default mikro comes with colors and also writes them to files, which can be turned off through configuration.

// src/config/config.default.ts
exporg default {
midwayLogger: {
clients: {
mikroLogger: {
transports: {
console: {
autoColors: false,
}
file: {
fileLogName: 'mikro.log'
},
},
}
}
},
mikro: {
dataSource: {
default: {
entities: [Author, Book, BookTag, Publisher, BaseEntity],
// ...
logger: 'mikroLogger',
colors: false,
}
},
}
}

Frequently Asked Questions

1. Node version

Mikro-orm there are some restrictions on Node version, it must be >= 14.0.0, so do the usage rules of @midwayjs/mikro components.

2. Identity Map

Mikro-orm internal query has a concept of Identity Map. Midway has added this function to all built-in Framework middleware. If it is used in non-requesting link call scenarios, such as src/configuration, the allowGlobalContext option can be turned on.

3. Multi-dataSource support

Like other databases, Midway supports the configuration of multiple data sources.

// src/config/config.default
import { Author, BaseEntity, Book, BookTag, Publisher } from '../entity';
import { SqlHighlighter } from '@mikro-orm/sql-highlighter';
import { join } from 'path';

export default (appInfo) => {
return {
mikro: {
dataSource: {
custom1: {
// ...
},
custom2: {
// ...
}
}
}
}
}

Note which data source you need to pass from when using.

// ...

@Provide()
export class BookController {

@InjectRepository(Book, 'custom1')
bookRepository: EntityRepository<Book>;

async findBookAndQuery() {
// ...
}
}