MikroORM v3 到 v4 升级完全指南:包拆分、类型安全改造与破坏性变更清单

发布时间:2026/9/27 10:05:23
MikroORM v3 到 v4 升级完全指南:包拆分、类型安全改造与破坏性变更清单 后端【免费下载链接】mikro-ormTypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, MS SQL Server, PostgreSQL and SQLite/libSQL databases.项目地址https://gitcode.com/gh_mirrors/mi/mikro-orm点击查看免费下载MikroORM v4 是一次里程碑式的大版本升级ORM 被拆分为 monorepo 多包结构、默认元数据提供器切换为ReflectMetadataProvider、EntityManager按数据库平台拆分出 SQL 与 Mongo 两种风味、wrap()辅助函数与Reference包装器的内部结构全面重构同时引入了LoadedT, P类型安全的加载提示与基于defaultRaw的 SQL 默认值语法。本文以官方 v4 升级指南见 docs/versioned_docs/version-7.1/upgrading-v3-to-v4.md为主线逐条拆解这些破坏性变更并结合作者当前仓库源码如 EntityManager.ts、wrap.ts、BaseEntity.ts、UnderscoreNamingStrategy.ts给出迁移前后的对照写法帮助你安全、平滑地把存量 v3 项目升级到 v4。升级前的环境前提v4 对运行环境提出了明确的最低版本要求升级前请先核对Node.js ≥ 10.13.0v4 放弃了对更早 Node 版本的支持官方文档明确 Support for older node versions was dropped。TypeScript ≥ 3.7同样放弃了更早 TypeScript 版本的支持。如果你仍在使用更低版本的 Node 或 TypeScript需要先升级工具链再执行代码层面的迁移。这两条是硬性门槛不会因项目是否用到某个特性而可以跳过。Monorepo 化从单包到多包拆分v4 最大的结构性变化是 ORM 从单一mikro-orm包拆分为多个独立发布的子包。升级后你需要同时安装mikro-orm/core与对应数据库的驱动包例如npm install mikro-orm/core mikro-orm/mysqlv4 的包清单如下摘自升级指南包名用途mikro-orm/core核心包包含EntityManager、EntityRepository、实体定义等与数据库无关的基础能力mikro-orm/reflection提供TsMorphMetadataProvider供需要 ts-morph 反射元数据的场景使用mikro-orm/cliCLI 支持依赖 entity-generator、migrator 与 knexmikro-orm/knexSQL 支持层mikro-orm/entity-generator实体生成器mikro-orm/migrations迁移工具mikro-orm/mysqlMySQL 驱动自带mysql2依赖mikro-orm/mariadbMariaDB 驱动mikro-orm/mysql-baseMySQL 与 MariaDB 的公共实现内部包mikro-orm/sqliteSQLite 驱动mikro-orm/postgresqlPostgreSQL 驱动mikro-orm/mongodbMongoDB 驱动值得注意的细节驱动包已内置数据库客户端依赖例如mikro-orm/mysql已经包含mysql2你可以把package.json中手动添加的mysql2依赖删除避免版本冲突。mikro-ormmeta 包仍然存在它重新导出 core、reflection、migrations、entity-generator 和 cli目的是便于平滑过渡。但官方明确建议不要同时安装mikro-orm与mikro-orm/core且优先使用mikro-orm/core因为 meta 包曾报告过一些奇怪的依赖问题。当前仓库v7 时代已演进为 packages 目录下的完整 monorepo 结构core包源码位于 packages/core/src各驱动包位于 packages/mysql/src、packages/mongodb/src 等印证了 v4 奠定的多包架构至今延续。默认元数据提供器切换为ReflectMetadataProviderv4 之前默认使用 ts-morph 做元数据发现v4 起默认改为ReflectMetadataProvider基于reflect-metadata反射。若仍希望使用 ts-morph需要显式安装并配置import { TsMorphMetadataProvider } from mikro-orm/reflection; await MikroORM.init({ metadataProvider: TsMorphMetadataProvider, // ... });官方文档提醒了两个配套要点ReflectMetadataProvider有若干局限完整清单见 metadata-providers.md正式文档目录为 docs/docs/metadata-providers.md中的 Limitations and requirements 一节。一个常见陷阱使用reflect-metadata时带属性初始化器的属性必须显式标注类型。例如Property() createdAt: Date new Date();如果不写: DateTypeScript 会推断出Object进而可能被映射为 JSON 列类型具体取决于驱动导致数据库 schema 与预期不符。说明仓库 docs 目录中该主题的现行版本见 docs/docs/metadata-providers.md本文引用的 v3→v4 升级指南位于 docs/versioned_docs/version-7.1/upgrading-v3-to-v4.md。SqlEntityManager与MongoEntityManagerEM 按平台拆分v4 中core包不再依赖 knex因此核心的EntityManager无法再提供返回QueryBuilder的方法。要使用createQueryBuilder()必须从 SQL 驱动包导入 SQL 风味的EntityManagerimport { EntityManager } from mikro-orm/mysql; // 或其他任意 SQL 驱动包 const em: EntityManager; const qb await em.createQueryBuilder(...);对应的Mongo 的aggregate()方法也需要从 Mongo 驱动包导入import { EntityManager } from mikro-orm/mongodb; const em: EntityManager; const ret await em.aggregate(...);官方指南特别说明SQL 风味的 EM 实际类名是SqlEntityManagerMongo 风味的实际类名是MongoEntityManager两者都同时以EntityManager别名导出——所以大多数情况下你只需修改 import 语句的来源包代码主体无需改动。这也解释了为什么当前仓库中 packages/sql/src 与 packages/mongodb/src 各自维护着平台特定的 EM 实现而 packages/core/src/EntityManager.ts 只保留数据库无关的通用逻辑。默认pivotTable连接表命名规则变化UnderscoreNamingStrategy与EntityCaseNamingStrategy的joinTableName()实现发生了改变。v3 行为连接表名由两个实体名构造为entity_a_to_entity_b忽略属性名。因此当同一对实体之间定义了多个 M:N 关系时连接表名会冲突你不得不在至少一个关系上手动指定pivotTable。v4 行为连接表名改为entity_a_coll_name其中collName是拥有侧集合属性的名字从而保证不同属性产生的连接表不会互相冲突。你依然可以在 M:N 关系的拥有侧使用pivotTable手动指定表名。这一行为在源码中得到了直接印证当前 UnderscoreNamingStrategy.ts 的joinTableName()实现为joinTableName(sourceEntity: string, targetEntity: string, propertyName: string, tableName?: string): string { return this.classToTableName(sourceEntity, tableName) _ this.classToTableName(propertyName); }即“源实体表名 属性名”的组合属性名成为表名的一部分EntityCaseNamingStrategy.ts 与之同构。抽象接口定义在 NamingStrategy.ts。迁移动作检查所有 M:N 关系。若 v3 中因冲突而手动指定过pivotTable升级后可以尝试删除手动命名让默认规则生成唯一表名若存量数据库已有按旧规则生成的连接表则需要通过pivotTable保持表名不变或执行一次表重命名迁移。目录发现机制变更entitiesDirs被移除v3 的entitiesDirs与entitiesDirsTs配置在 v4 中被移除统一改用entities与entitiesTsentities现在可以混合包含目录路径、指向实体的 glob、实体类引用、EntitySchema实例entitiesTs用于ts-node场景未指定时默认回退到entities对大多数项目来说迁移动作就是把entitiesDirs改名为entities。MikroORM.init({ entities: [dist/**/entities, dist/**/*.entity.js, FooBar, FooBaz], entitiesTs: [src/**/entities, src/**/*.entity.ts, FooBar, FooBaz], });配套地discovery.tsConfigPath配置也被移除。它此前仅服务于TsMorphMetadataProvider在未显式提供entitiesDirsTs时使用v4 中 ts-morph 发现改读d.ts文件——这些文件应当位于编译产物旁边因此不再需要 tsconfig 路径配置。如果你在 v3 里配置了tsConfigPath升级时直接删除该配置项即可。wrap()辅助函数、WrappedEntity接口与Reference包装器重构这是 v4 中 API 形状变化最大的一处直接影响实体类型的书写方式v3WrappedEntity接口的所有方法与属性在实体发现阶段被直接注入实体原型wrap(entity)返回实体本身。v4实体原型上只注入一个属性__helper: WrappedEntity且WrappedEntity从接口变成了真实类wrap(entity)不再返回实体而是返回WrappedEntity实例其上只有公开方法init、assign、isInitialized等若要访问__meta、__em等内部属性必须显式传第二个参数wrap(entity, true)Reference类上带__前缀的内部方法也被移除同样改用wrap(ref, true)访问。当前源码中 wrap.ts 的实现忠实体现了这一设计export function wrapT extends object(entity: T, preferHelper: true): IWrappedEntityInternalT; export function wrapT extends object(entity: T, preferHelper?: false): IWrappedEntityT; export function wrapT extends object( entity: T Dictionary, preferHelper false, ): IWrappedEntityT | IWrappedEntityInternalT { if (!entity) return entity; if (entity.__baseEntity !preferHelper) { return entity as unknown as IWrappedEntityT; } return entity.__helper ?? entity; }注意源码中还有一个细节当实体继承自BaseEntity带有__baseEntity标记且未请求内部 helper 时wrap(entity)会返回实体本身——这正是官方指南所说的“改用经典继承即可让wrap(entity)返回你的实体”。替代方案不再使用接口合并interface merging withWrappedEntity而是继承mikro-orm/core导出的BaseEntity类。当前 BaseEntity.ts 中它提供了isInitialized()、populated()、populate()、toReference()、toObject()等便捷方法全部委托给内部 helper 实现。例如import { BaseEntity } from mikro-orm/core; class Author extends BaseEntity { // 实体字段定义... }迁移动作把原来通过接口合并注入的辅助方法调用如entity.isInitialized()迁移到继承BaseEntity或改走wrap(entity)任何依赖__meta、__em的代码改为wrap(entity, true)。persist()/remove()的flush参数被移除v4 中persist()与remove()的第二个参数flush被删除。两者现在都是同步方法返回thisEM 本身不再隐式触发 flush需要显式调用.flush()——官方推荐使用流式接口fluent interface写法// v3 await em.persist(jon, true); await em.remove(Author, jon, true); // v4 await em.persist(jon).flush(); await em.remove(jon).flush();当前源码 EntityManager.ts 中persist()与remove()的签名均为(entity | ReferenceEntity | Iterable...) this接受实体实例或Reference包装也支持可迭代对象批量处理并返回this供链式调用与指南描述完全一致persistEntity extends object(entity: Entity | ReferenceEntity | IterableEntity | ReferenceEntity): this removeEntity extends object(entity: Entity | ReferenceEntity | IterableEntity | ReferenceEntity): this迁移动作全局搜索em.persist(、em.remove(调用删除布尔参数并在需要立即落库的位置补上.flush()。注意这里还有一处 API 变更——removeEntity()已被移除统一使用em.remove()两者签名现在几乎相同。remove()只接受实体实例条件删除改用nativeDelete()v3 的em.remove()既接受实体实例也接受条件对象传条件时会直接触发原生删除查询不经过事务与生命周期钩子。v4 简化了这一行为em.remove()只接受实体实例或Reference删除交给UnitOfWork在 flush 时统一处理想按条件直接发删除 SQL请显式调用em.nativeDelete()。// v3 await em.remove(Author, 1); // 直接发查询 // v4 await em.nativeDelete(Author, 1);源码同样给出了佐证remove()的实现注释与校验信息明确写着 “To remove entities by condition, useem.nativeDelete()”且对非实体入参抛出You need to pass entity instance or reference to em.remove(). To remove entities by condition, use em.nativeDelete().的报错见 EntityManager.ts 第 2722–2747 行附近。这也意味着 v3 中“传条件删除”绕过钩子的捷径在 v4 已不可用——所有删除都纳入工作单元管理保证钩子、级联与事务一致性。类型安全的引用LoadedT, P与get()同步取值v4 起 EM 的查询方法返回LoadedT, P而不是裸实体T。这个类型会自动为引用/集合添加同步的get()方法——对引用返回实体对集合返回实体数组。相关行为变化Reference.get()现在只在正确的Loaded类型提示下可用作为同步取值器功能类似unwrap()原来get()的异步加载功能改由Reference.load(prop)提供。em.find()等方法的类型参数变为两个。由于 TypeScript 不支持部分类型推断如果你显式指定了T却没有同时给出加载提示populate hint推断会失效。该场景主要出现在“接口 EntitySchema”的无类用法中——此时可以直接把EntitySchema实例作为第一个参数传入从而获得正确的类型推断const author await em.findOne(AuthorSchema, { ... }, [books]); console.log(author.books.get()); // get() 现在被正确推断迁移动作如果代码里手动写过Reference.get()依赖其异步加载行为改为Reference.load(prop)检查显式指定泛型参数的find/findOne调用必要时改用EntitySchema实例作为首参以恢复类型推断。自定义类型Custom Type的类型安全与序列化变化类型参数变为两个泛型Type类现在接受输入类型与输出类型两个类型参数输入默认string输出默认等于输入。若你的方法有严格类型标注可能需要显式给出这两个类型参数。序列化行为反转v3 中自定义类型会被序列化为数据库值v4 默认使用运行时值。如需自定义序列化结果请实现toJSON()方法。属性默认值default与defaultRaw拆分v3 中default选项按原样使用字符串必须手动加引号例如Property({ default: foo bar })。v4 中default的类型改为string | number | boolean | null字符串值会被自动加引号要使用 SQL 函数必须改用defaultRawProperty({ defaultRaw: now() }) createdAt: Date;迁移动作把default中带手工引号的字符串去掉引号把now()、CURRENT_TIMESTAMP等 SQL 函数表达式迁移到defaultRaw。autoFlush移除与persistLater()/removeLater()弃用autoFlush配置选项被移除persistLater()与removeLater()方法也被弃用。分别改用persist()与remove()配合显式flush()。IdEntity、UuidEntity、MongoEntity接口被移除这三个接口在 v3 中“实际上从未被需要”v4 直接移除。若你的实体继承或引用了它们请删除相关继承并改用普通字段定义如PrimaryKey()Property()。MongoDB 不再是默认驱动v3 默认 MongoDBv4 起你必须显式指定平台通过type或driver选项await MikroORM.init({ type: postgresql, // 或 mongo / mysql / mariadb / sqlite // 或者driver: MyCustomDriver, });v4 支持的平台类型为[mongo, mysql, mariadb, postgresql, sqlite]。升级时请务必检查初始化配置否则 ORM 将无法确定使用哪个驱动。查询高亮从 Highlight.js 到可插拔 highlighterv3 内部使用 Highlight.js 为 CLI 中的 SQL、Mongo 查询、迁移与生成的实体做高亮。该库体积庞大对使用 webpack 打包 lambda 部署的场景造成明显性能负担。v4 的调整高亮默认关闭提供两个可选高亮器需自行安装后通过highlighter配置启用import { SqlHighlighter } from mikro-orm/sql-highlighter; MikroORM.init({ highlighter: new SqlHighlighter(), // ... });MongoDB 场景可使用mikro-orm/mongo-highlighter。不安装任何高亮器则保持默认关闭状态。迁移速查清单把以上全部变更浓缩为一份可逐项勾选的清单升级 Node.js 到 ≥ 10.13.0TypeScript 到 ≥ 3.7安装mikro-orm/core 对应驱动包移除冗余的mysql2等数据库客户端依赖不要混装mikro-ormmeta 包与mikro-orm/core若需要 ts-morph安装mikro-orm/reflection并显式配置metadataProvider: TsMorphMetadataProvider否则接受默认的ReflectMetadataProvider并为带初始化的属性补上显式类型createQueryBuilder()相关代码改从 SQL 驱动包导入EntityManageraggregate()相关代码改从mikro-orm/mongodb导入检查 M:N 关系连接表名处理手动pivotTable与存量表名将entitiesDirs/entitiesDirsTs改名为entities/entitiesTs删除discovery.tsConfigPath处理wrap()返回值变化内部属性改走wrap(entity, true)考虑继承BaseEntity替代接口合并删除persist()/remove()的 flush 布尔参数并补.flush()用nativeDelete()替代条件删除处理Reference.get()与LoadedT, P的类型变化EntitySchema作为查询首参恢复推断自定义类型补齐双类型参数需要时实现toJSON()default去引号、SQL 函数迁移到defaultRaw删除autoFlush、persistLater()、removeLater()、IdEntity/UuidEntity/MongoEntity显式配置type或driverMongo 不再是默认按需安装并配置mikro-orm/sql-highlighter/mikro-orm/mongo-highlighter进一步阅读完整 v3→v4 升级指南原文docs/versioned_docs/version-7.1/upgrading-v3-to-v4.md后续版本升级路径upgrading-v4-to-v5、upgrading-v5-to-v6、upgrading-v6-to-v7元数据提供器详解metadata-providers.md核心实现源码EntityManager.ts、wrap.ts、WrappedEntity.ts、BaseEntity.ts、Reference.ts命名策略实现UnderscoreNamingStrategy.ts、EntityCaseNamingStrategy.ts、NamingStrategy.ts赞分享后端【免费下载链接】mikro-ormTypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, MS SQL Server, PostgreSQL and SQLite/libSQL databases.项目地址https://gitcode.com/gh_mirrors/mi/mikro-orm点击查看免费下载相关推荐MikroORM v3 到 v4 升级完全指南破坏性变更、包拆分与迁移要点MikroORM v3 到 v4 升级完全指南破坏性变更、包拆分与迁移要点 本指南以 MikroORM 官方文档 docs/versioned_docs/ve后端MikroORM v3 升级到 v4 完整迁移指南Monorepo 拆分、类型安全重构与破坏性变更全解析MikroORM v3 升级到 v4 完整迁移指南Monorepo 拆分、类型安全重构与破坏性变更全解析 本文基于 MikroORM 官方升级文档 docs后端MikroORM v3 到 v4 升级迁移完全指南Monorepo 拆分、EntityManager 重构与破坏性变更全解析MikroORM v3 到 v4 升级迁移完全指南Monorepo 拆分、EntityManager 重构与破坏性变更全解析 本篇技术指南面向正在使用 Mik后端上一篇3分钟上手League Akari英雄联盟玩家的终极自动化工具箱下一篇Saladict 机器翻译源扩展实战阿里、火山、小牛自定义 API 的设计与实现解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询