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.0version 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:
-
- Define Entity
-
- Configure the data source
-
- Get the EntityModel to call
For more information about Entity code, see Example.
Directory structure
A basic reference directory structure is as follows.
MyProject
├── src
│ ├── config
│ │ └── config.default.ts
│ ├── entity
│ │ ├── book.entity.ts
│ │ ├── index.ts
│ │ └── base.ts
│ ├── configuration.ts
│ └── service
├── .gitignore
├── package.json
├── README.md
└── tsconfig.json
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.
// src/entity/book.entity.ts
import { Cascade, Collection, Entity, ManyToMany, ManyToOne, Property } from '@mikro-orm/core';
import { Author, BookTag, Publisher } from './index';
import { BaseEntity } from './base';
@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.
- mikro v6
- mikro v5
// 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: {
dbName: join(__dirname, '../../test.sqlite'),
driver: SqliteDriver, // SQLite is used as an example here.
allowGlobalContext: true,
// Object format
entities: [Author, Book, BookTag, Publisher, BaseEntity],
// The following scanning form is supported. For compatibility, we can match both .js and .ts files at the same time
entities: [
'entity', // Specify the directory
'**/entity/*.entity.{j,t}s', // Wildcard with suffix matching
],
}
}
}
}
}
// src/config/config.default
import { Author, BaseEntity, Book, BookTag, Publisher } from '../entity';
import { join } from 'path';
export default (appInfo) => {
return {
mikro: {
dataSource: {
default: {
dbName: join(__dirname, '../../test.sqlite')
Type: 'sqlite', // SQLite is used as an example here.
allowGlobalContext: true,
// Object format
entities: [Author, Book, BookTag, Publisher, BaseEntity],
// The following scanning form is supported. For compatibility, we can match both .js and .ts files at the same time
entities: [
'entity', // Specify the directory
'**/entity/*.entity.{j,t}s', // Wildcard with suffix matching
],
}
}
}
}
}
The entities field configuration of mikro has been processed by the framework, please do not refer to the original document.
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().
-
- Since v5.7,
persistandflushetc. onRepository(shortcuts to methods onEntityManager) were marked as deprecated, and planned to remove them in v6. Please use those APIs onEntityMangerdirectly instead of onRepository.
- Since v5.7,
-
- v6 has been completely deprecated the above interface
// src/service/book.service.ts
import { Book } from './entity/book.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;
}
}