MikroORM
本章节介绍用户如何在 midway 中使用 MikroORM。 MikroORM 是基于数据映射器、工作单元和身份映射模式的 Node.js 的 TypeScript ORM。
MikroORM 的官网文档在 这里。
相关信息:
描述 | |
---|---|
可用于标准项目 | ✅ |
可用于 Serverless | ✅ |
可用于一体化 | ✅ |
包含独立主框架 | ❌ |
包含独立日志 | ❌ |
关于升级
- 从
v3.14.0
版本的组件开始,支持 mikro v5/v6 版本,由于 mikro v5 到 v6 有较大的变化,如从 mikro 老版本升级请提前阅读 Upgrading from v5 to v6 - 组件示例已更新为 v6 版本
安装组件
安装 mikro 组件,提供接入 mikro-orm 的能力。
$ npm i @midwayjs/mikro@3 @mikro-orm/core --save
或者在 package.json
中增加如下依赖后,重新安装。
{
"dependencies": {
"@midwayjs/mikro": "^3.0.0",
"@mikro-orm/core": "^6.0.2",
// ...
},
"devDependencies": {
// ...
}
}
同时,还需要引入对应数据库的适配包。
比如:
{
"dependencies": {
// sqlite
"@mikro-orm/sqlite": "^6.0.2",
// mysql
"@mikro-orm/mysql": "^6.0.2",
},
"devDependencies": {
// ...
}
}
更多驱动程序请查看 官方文档。
引入组件
在 src/configuration.ts
引入 mikro 组件,示例如下。
// configuration.ts
import { Configuration } from '@midwayjs/core';
import * as mikro from '@midwayjs/mikro';
import { join } from 'path';
@Configuration({
imports: [
// ...
mikro // 加载 mikro 组件
],
importConfigs: [
join(__dirname, './config')
]
})
export class MainConfiguration {
}
基础使用
和其他 orm 框架类似,都是分为几个步骤:
- 1、定义 Entity
- 2、配置数据源
- 3、获取 EntityModel 进行调用
下面的更多 Entity 代码请查看 示例。
目录结构
一个基础的参考目录结构如下。
MyProject
├── src
│ ├── config
│ │ └── config.default.ts
│ ├── entity
│ │ ├── book.entity.ts
│ │ ├── index.ts
│ │ └── base.ts
│ ├── configuration.ts
│ └── service
├── .gitignore
├── package.json
├── README.md
└── tsconfig.json
定义 Entity
定义基础的 Entity。
// 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();
}
定义实际的 Entity,包含一对多,多对多等关系。
// 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;
}
}
配置数据源
mikro v5 和 v6 略有不同。
- 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 做示例
allowGlobalContext: true,
// 实体形式
entities: [Author, Book, BookTag, Publisher, BaseEntity],
// 支持如下的扫描形式,为了兼容我们可以同时进行.js和.ts匹配️
entities: [
'entity', // 指定目录
'**/entity/*.entity.{j,t}s', // 通配加后缀匹配
],
}
}
}
}
}
// 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 做示例
allowGlobalContext: true,
// 实体形式
entities: [Author, Book, BookTag, Publisher, BaseEntity],
// 支持如下的扫描形式,为了兼容我们可以同时进行.js和.ts匹配️
entities: [
'entity', // 指定目录
'**/entity/*.entity.{j,t}s', // 通配加后缀匹配
],
}
}
}
}
}
提示
mikro 的 entities
字段配置已经经过框架处理,该字段配置请不要参考原始文档。
增删查改
在业务代码中,可以使用 InjectRepository
注入 Repository
对象执行简单的查询操作。其它的增删改操作可以通过配合EntityManger
的 persist
和 flush
接口来实现,使用 InjectEntityManager
可以直接注入 EntityManager
对象,也可以通过repository.getEntityManager()
获取。
警告
// 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'; // 需要使用数据库驱动对应的类来执行操作
@Provide()
export class BookService {
@InjectRepository(Book)
bookRepository: EntityRepository<Book>;
@InjectEntityManager()
em: EntityManager;
async queryByRepo() {
// 使用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' } });
// 标记保存Book
this.em.persist(book);
// 执行所有变更
await this.em.flush();
return book;
}
}
高级功能
获 取数据源
数据源即创建出的数据源对象,我们可以通过注入内置的数据源管理器来获取。
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();
// ...
}
}
从 v3.8.0 开始,也可以通过装饰器注入。
import { Configuration } from '@midwayjs/core';
import { InjectDataSource } from '@midwayjs/mikro';
import { MikroORM, IDatabaseDriver, Connection } from '@mikro-orm/core';
@Configuration({
// ...
})
export class MainConfiguration {
// 注入默认数据源
@InjectDataSource()
defaultDataSource: MikroORM<IDatabaseDriver<Connection>>;
// 注入自定义数据源
@InjectDataSource('default1')
customDataSource: MikroORM<IDatabaseDriver<Connection>>;
async onReady(container: IMidwayContainer) {
// ...
}
}