胖蔡说技术
随便扯扯

MikroORM一款基于数据映射器、工作单元和身份映射模式的Node.js的TypeScript ORM

介绍

MikroORM是基于数据映射器、工作单元和身份映射模式的Node.jsTypeScript ORM。在本指南中,您将了解这些单词的含义、如何建立一个简单的API项目、如何测试它等等。

本指南的目的是展示MikroORM最重要的功能以及一些更小众的功能。它将引导您使用以下技术为博客创建一个简单的API

  • SQLite驱动程序的MikroORM
  • Fastify作为网络框架
  • 测试用Vitest
  • ECMAScript模块
  • JWT身份验证
  • 通过ts变形进行反射

ORM由几个包组成,我们将使用其中的重要包:

  • @mikro-orm/core: 带有ORM代码的主包
  • @mikro-orm/cli: CLI程序包,需要在本地安装
  • @mikro-orm/sqlite: sqlite驱动程序包(您也可以使用不同的驱动程序)
  • @mikro-orm/reflection: 启用具有ts变形反射的DRY实体
  • @mikro-orm/migrations: 用于管理架构迁移的包
  • @mikro-orm/seeder: 用于为数据库设定测试数据种子的包

核心和驱动程序包是必需的,此列表的其余部分是可选的,如果您愿意,可以是开发依赖项。我们将使用sqlite驱动程序,主要是为了简单起见,因为它不需要任何额外的设置,并且提供了一个方便的内存数据库,我们将在测试中使用它。

还有更多的程序包,有些程序包也位于mikro-orm/mikro-ormmonorepo之外,如@mikro-or/nestjs@mikro-orm/sql-highlighter-与monorepo中的程序包不同,这些程序包通常具有不同的版本行。

当前可用驱动程序的完整列表:

  • @mikro-orm/mysql
  • @mikro-orm/mariadb
  • @mikro-orm/postgresql
  • @mikro-orm/sqlite
  • @mikro-orm/better-sqlite
  • @mikro-orm/mongodb

安装

首先通过您选择的软件包管理器安装模块,可以使用如下任一工具。也不要忘记安装数据库驱动程序:

1、使用npm

# for mongodb
npm install @mikro-orm/core @mikro-orm/mongodb

# for mysql (works with mariadb too)
npm install @mikro-orm/core @mikro-orm/mysql

# for mariadb (works with mysql too)
npm install @mikro-orm/core @mikro-orm/mariadb

# for postgresql (works with cockroachdb too)
npm install @mikro-orm/core @mikro-orm/postgresql

# for sqlite
npm install @mikro-orm/core @mikro-orm/sqlite

# for better-sqlite
npm install @mikro-orm/core @mikro-orm/better-sqlite

2、使用yarn

# for mongodb
yarn add @mikro-orm/core @mikro-orm/mongodb

# for mysql (works with mariadb too)
yarn add @mikro-orm/core @mikro-orm/mysql

# for mariadb (works with mysql too)
yarn add @mikro-orm/core @mikro-orm/mariadb

# for postgresql (works with cockroachdb too)
yarn add @mikro-orm/core @mikro-orm/postgresql

# for sqlite
yarn add @mikro-orm/core @mikro-orm/sqlite

# for better-sqlite
yarn add @mikro-orm/core @mikro-orm/better-sqlite

3、使用pnpm

# for mongodb
pnpm add @mikro-orm/core @mikro-orm/mongodb

# for mysql (works with mariadb too)
pnpm add @mikro-orm/core @mikro-orm/mysql

# for mariadb (works with mysql too)
pnpm add @mikro-orm/core @mikro-orm/mariadb

# for postgresql (works with cockroachdb too)
pnpm add @mikro-orm/core @mikro-orm/postgresql

# for sqlite
pnpm add @mikro-orm/core @mikro-orm/sqlite

# for better-sqlite
pnpm add @mikro-orm/core @mikro-orm/better-sqlite

接下来,您需要通过以下方式在tsconfig.json中启用对decorator以及esModuleInterop的支持(装饰器是选择性的,如果您使用不同的方式来定义实体元数据(如EntitySchema),则不需要启用它们。):

"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"esModuleInterop": true

然后调用MikroORM.init作为引导应用程序的一部分:

import { MikroORM } from '@mikro-orm/postgresql'; // or any other driver package

const orm = await MikroORM.init({
  entities: ['./dist/entities'], // path to your JS entities (dist), relative to `baseDir`
  dbName: 'my-db-name',
});
console.log(orm.em); // access EntityManager via `em` property

要访问特定于驱动程序的方法,如em.createQueryBuilder(),您需要从驱动程序包导入MikroORM/EntityManager/EntityRepository类。或者,您可以将orm.em强制转换为从驱动程序包导出的EntityManager

import { EntityManager } from '@mikro-orm/postgresql';
const em = orm.em as EntityManager;
const qb = em.createQueryBuilder(...);

基于文件位置配置entity

还可以通过实体阵列提供存储实体的路径。路径是通过内部globby解析的,因此可以使用globbing模式,包括负globs

const orm = await MikroORM.init({
  entities: ['./dist/app/**/*.entity.js'],  // 基于项目目录配置最终部署文件位置
  entitiesTs: ['./src/app/**/*.entity.ts'], // 基于当前项目目录配置ts所在源码位置
  // ...
});

如果在基于文件夹的查找中遇到问题,请尝试使用mikro orm debug CLI命令检查实际使用的路径。

TypeScript中的实体配置

默认的元数据提供程序是ReflectMetadataProvider。如果要使用基于ts-morph的发现(通过编译器API读取实际的ts类型),则需要安装@mikro-orm/reflection包。

import { MikroORM } from '@mikro-orm/postgresql';
import { TsMorphMetadataProvider } from '@mikro-orm/reflection';

const orm = await MikroORM.init({
  metadataProvider: TsMorphMetadataProvider,
  // ...
});

您也可以使用不同的默认ReflectMetadataProvider,甚至可以编写自定义的ReflectMetadata Provider。使用EntitySchema是定义实体的另一种方式,完全不依赖于元数据提供程序。

import { MikroORM } from '@mikro-orm/postgresql';

const orm = await MikroORM.init({
  // default since v4, so not needed to specify explicitly
  metadataProvider: ReflectMetadataProvider,
  // ...
});

同步初始化

与异步MikroORM.init方法相反,您可以更喜欢使用同步变体initSync。这种方法有一些局限性:

  • 数据库连接将在您第一次与数据库交互时建立(或者您可以显式使用orm.connect()
  • 没有加载配置文件,options参数是必需的
  • 不支持基于文件夹的发现
  • 不检查不匹配的包版本

RequestContext 

现在,您需要为每个请求派生实体管理器,这样它们的标识映射就不会发生冲突。要执行此操作,请使用RequestContext帮助程序:

const app = express();

app.use((req, res, next) => {
  RequestContext.create(orm.em, next);
});

您应该在请求处理程序之前和任何使用ORM的自定义中间件之前将此中间件注册为最后一个中间件。当您在queryParserbodyParser等请求处理中间件之前注册它时,可能会出现问题,所以一定要在它们之后注册上下文。

Entity定义

现在,您可以开始定义Entity(在其中一个Entity文件夹中)。如下是一个简单Entity定义的实例:

// ./entities/Book.ts
@Entity()
export class Book {

  @PrimaryKey()
  id: bigint;

  @Property()
  title: string;

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

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

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

}

或者,如果要使用UUID主键:

// ./entities/Book.ts
import { v4 } from 'uuid';

@Entity()
export class Book {

  @PrimaryKey({ type: 'uuid' })
  uuid = v4();

  // ...

}

EntityManager

定义实体后,可以通过EntityManager开始使用ORM

若要将实体状态保存到数据库,您需要将其持久化。persist确定是使用insert还是update,并计算适当的更改集。尚未持久化(没有标识符)的实体引用将自动级联持久化。

// use constructors in your entities for required parameters
const author = new Author('Jon Snow', 'snow@wall.st');
author.born = new Date();

const publisher = new Publisher('7K publisher');

const book1 = new Book('My Life on The Wall, part 1', author);
book1.publisher = publisher;
const book2 = new Book('My Life on The Wall, part 2', author);
book2.publisher = publisher;
const book3 = new Book('My Life on The Wall, part 3', author);
book3.publisher = publisher;

// just persist books, author and publisher will be automatically cascade persisted
await em.persist([book1, book2, book3]).flush();

要从数据库中获取实体,可以使用EntityManagerfind()findOne()

const authors = em.find(Author, {});

for (const author of authors) {
  console.log(author); // instance of Author entity
  console.log(author.name); // Jon Snow

  for (const book of author.books) { // iterating books collection
    console.log(book); // instance of Book entity
    console.log(book.title); // My Life on The Wall, part 1/2/3
  }
}

设置命令行工具

MikroORM附带了许多在开发过程中非常有用的命令行工具,如SchemaGeneratorEntityGenerator。您可以从NPM二进制目录调用此命令,也可以使用npx

# install the CLI package first!
$ yarn add @mikro-orm/cli

# manually
$ node node_modules/.bin/mikro-orm

# via npx
$ npx mikro-orm

# or via yarn
$ yarn mikro-orm

为了使CLI能够访问您的数据库,您需要创建导出orm配置的mikro-orm.config.js文件。

要启用TypeScript支持,请将useTsNode标志添加到package.json文件的mikro-orm部分。默认情况下,当未启用useTsNode时,CLI将忽略.ts文件,因此,如果您想排除这种行为,请启用alwaysAllowTs选项。如果您想将MikroORMBun一起使用,这将非常有用,Bun具有开箱即用的TypeScript支持。

您还可以在package.json中设置mikro-orm.config.*文件的可能路径阵列,以及使用不同的文件名。package.json文件可以位于当前工作目录中,也可以位于其父文件夹中。

// package.json
{
  "name": "your-app",
  "dependencies": { ... },
  "mikro-orm": {
    "useTsNode": true,
    "configPaths": [
      "./src/mikro-orm.config.ts",
      "./dist/mikro-orm.config.js"
    ]
  }
}

控制这些CLI相关设置的另一种方法是使用环境变量:

  • MIKRO_ORM_CLI_CONFIGORM配置文件的路径
  • MIKRO_ORM_CLI_USE_TS_NODE:为TypeScript支持注册TS节点
  • MIKRO_ORM_CLI_TS_CONFIG_PATHtsconfig.json的路径(用于TS节点)
  • MIKRO_ORM_CLI_ALWAYS_ALLOW_TS:启用不使用TS节点的.TS文件
  • MIKRO_ORM_CLI_VERBOSE:启用详细日志记录(例如,打印种子程序或模式困难中使用的查询)

或者,您也可以通过--config选项指定配置路径:

$ npx mikro-orm debug --config ./my-config.ts

当您运行应用程序时(只要它是process.argv的一部分),而不仅仅是当您使用CLI时,–config标志也会受到尊重。

MikroORM将始终尝试根据configPaths中的顺序加载第一个可用的配置文件。如果禁用了useTsNode,或者尚未注册或检测到ts节点,则ts配置文件将被忽略。

创建配置对象的首选方式是使用defineConfig助手。即使在JavaScript文件中,它也将提供智能感知,而不需要通过jsdoc进行类型提示:

import { defineConfig } from '@mikro-orm/sqlite';

export default defineConfig({
  entities: [Author, Book, BookTag],
  dbName: 'my-db-name',
  // this is inferred as you import `defineConfig` from sqlite package
  // driver: SqliteDriver,
});

如果从驱动程序包导入帮助程序,则使用defineConfig还会自动为您推断驱动程序选项。这意味着您不必显式地提供驱动程序选项。

或者,可以使用“选项”类型:

// ./src/mikro-orm.config.ts
import { Options } from '@mikro-orm/sqlite';

const config: Options = {
  entities: [Author, Book, BookTag],
  dbName: 'my-db-name',
  driver: SqliteDriver,
};

export default config;

正确设置CLI配置后,可以省略MikroORM.init()options参数,CLI配置将自动使用。如果您使用使用摇树的捆扎机,此过程可能会失败。由于配置文件没有在任何地方静态引用,因此不会对其进行编译,因此最好的方法是显式提供配置:

import config from './mikro-orm.config';
const orm = await MikroORM.init(config);

现在您应该可以开始使用CLI了。CLI帮助中列出了所有可用的命令:

$ npx mikro-orm

Usage: mikro-orm <command> [options]

Commands:
  mikro-orm cache:clear             Clear metadata cache
  mikro-orm cache:generate          Generate metadata cache
  mikro-orm generate-entities       Generate entities based on current database
                                    schema
  mikro-orm database:create         Create your database if it does not exist
  mikro-orm database:import <file>  Imports the SQL file to the database
  mikro-orm seeder:run              Seed the database using the seeder class
  mikro-orm seeder:create <seeder>  Create a new seeder class
  mikro-orm schema:create           Create database schema based on current
                                    metadata
  mikro-orm schema:drop             Drop database schema based on current
                                    metadata
  mikro-orm schema:update           Update database schema based on current
                                    metadata
  mikro-orm schema:fresh            Drop and recreate database schema based on
                                    current metadata
  mikro-orm migration:create        Create new migration with current schema
                                    diff
  mikro-orm migration:up            Migrate up to the latest version
  mikro-orm migration:down          Migrate one step down
  mikro-orm migration:list          List all executed migrations
  mikro-orm migration:check         Check if migrations are needed. Useful for
                                    bash scripts.
  mikro-orm migration:pending       List all pending migrations
  mikro-orm migration:fresh         Clear the database and rerun all migrations
  mikro-orm debug                   Debug CLI configuration

Options:
      --config   Set path to the ORM configuration file                 [string]
  -v, --version  Show version number                                   [boolean]
  -h, --help     Show help                                             [boolean]

Examples:
  mikro-orm schema:update --run  Runs schema synchronization

赞(1) 打赏
转载请附上原文出处链接:胖蔡说技术 » MikroORM一款基于数据映射器、工作单元和身份映射模式的Node.js的TypeScript ORM
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

请小编喝杯咖啡~

支付宝扫一扫打赏

微信扫一扫打赏