Node好用的orm框架有没有

11 阅读3分钟

MikroORM V7发布后,nestjs orm框架选择不再纠结

相关链接

github.com/oofengoo/ne…

mikro-orm.io/docs/guide

作为一名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支持下

github.com/oofengoo/ne…