MikroORM V7发布后,nestjs orm框架选择不再纠结
相关链接
作为一名7年经验的Node全栈开发工程师,我做过很多node项目,从Express到NestJS两大框架都有过实战经验。经过权衡,我最终选择NestJS作为主要开发框架,因为它有清晰的模块化架构,很适合做长期维护的项目,彻底解决了我在框架选择上的困扰。但与之形成鲜明对比的是,Node生态中的orm框架,却一直让我纠结不已。目前主流的orm框架如TypeOrm、Prisma、MikroOrm我都有用过,说实话,没有一款用的很顺手,要么查询控制力低,要么类型不安全,要么时区有问题,要么不适合大项目,每个orm都存在一些缺陷,没有一个适合作为为主力的orm。
先说说TypeOrm,这个知名度确实比较高,接触node项目的一般绕不过它,它的功能确实足够强大,生态也相对完善,但它的弊端也同样明显,模型定义是使用装饰器模式的,类型推导不够严谨,在复杂业务场景下很容易出现类型不安全的问题,最重要的是,作者基本不考虑维护了,github上积压了大量未处理的issue,在项目遇到一些极端bug时候,只能靠自己解决,比较麻烦。
再看Prisma,我之前看介绍号称是下一代的orm框架,我也以为它能作为我的主力orm,实际体验过后,还是存在很多问题,例如一直没解决的时区问题,查询控制力不灵活。我感觉只适合做做小项目。
然后再说下MikroORM。当时是在技术群的群友介绍下了解了它,看中了它比TypeORM更严谨的类型支持和更灵活的查询能力,但它的底层是Knex,性能比较差,在复杂的联表查询下可能会有问题,也不敢把它作为主力orm。我使用的是V6版本。
这种选择困难随着Mikroorm V7的发布才结束,让我不用在众多orm框架中纠结,算是目前orm框架中的最优解了。
MikroORM v7的升级,是属于破坏性更新了,最让我惊喜的两大核心调整,恰好解决了之前所有ORM框架的痛点。
它的底层从Knex改为kysely,性能更强,彻底解决了v6版本的性能瓶颈。
它的实体定义现在是推荐用defineEntiy,相比之前的装饰器模式有更好的类型安全和推导。
// 装饰器模式
import { Entity, PrimaryKey, Property, Index } from "@mikro-orm/decorators/legacy";
@Entity()
export class Role {
@PrimaryKey()
id!: number;
@Property({ length: 50 })
name!: string;
@Property({ unique: true, length: 50 })
@Index()
code!: string;
@Property({ nullable: true, length: 200 })
description?: string;
@Property({ default: false })
isSuperAdmin!: boolean;
@Property({ onCreate: () => new Date() })
createdAt: Date = new Date();
@Property({ onUpdate: () => new Date(), onCreate: () => new Date() })
updatedAt: Date = new Date();
}
// defineEntity模式
import { defineEntity, type InferEntity, p } from "@mikro-orm/core";
export const Role = defineEntity({
name: "Role",
properties: {
id: p.integer().primary(),
name: p.string().length(50),
code: p.string().length(50).unique().index(),
description: p.string().length(200).nullable().$type<string | undefined>(),
isSuperAdmin: p.boolean().default(false),
createdAt: p.datetime().onCreate(() => new Date()),
updatedAt: p
.datetime()
.onCreate(() => new Date())
.onUpdate(() => new Date()),
},
});
export type Role = InferEntity<typeof Role>;
另外MikroORM的查询兼顾 了便捷和灵活的特点,既可以用封装好的语法快速开发,也可以直接用底层暴露kysely实例来进行复杂的sql操作。
async findAll(query: QueryRoleParams): Promise<IPaginationRespData<RoleListResult>> {
const { name } = query;
const pageIndex = query.pageIndex ?? 1;
const pageSize = query.pageSize ?? 10;
const where = {
...(name && { name: { $like: `%${name}%` } }),
};
const [roles, total] = await this.em.findAndCount(Role, where, {
limit: pageSize,
offset: (pageIndex - 1) * pageSize,
orderBy: { createdAt: "DESC" },
fields: extractFields(RoleListResult),
});
return toPage(
roles.map((role) => this.toRoleListResult(role)),
{
pageIndex,
pageSize,
total,
}
);
}
如果你还在为Node ORM选择困难,我建议是直接用MikroORM V7,可以专注业务逻辑开发,不需要再为各种ORM框架的问题而纠结了。
我开源了nestjs-mikroorm的开箱即用的框架,对NestJS或者MikroORM有兴趣的可以看看,希望给个Star支持下