从其他 ORM 迁移到 Prisma
本教程共 54 篇 · 第 51 篇 · 更新于 2026-08-11 · 约 5 分钟阅读
本节目标:掌握从任意 ORM 迁到 Prisma 的通用流程,看懂 schema-first 与 code-first 的本质区别,能判断自己的项目该不该迁移。
先理解两种建模哲学
如 §01 所述,Prisma 采用 schema-first(Schema 文件驱动)建模,与 code-first 路线的完整对比见第 01 章。这里只保留迁移视角的对比:
| 维度 | schema-first(Prisma) | code-first(Drizzle/TypeORM) |
|---|---|---|
| 模型定义 | schema.prisma 声明式文件 | TS 代码 / 装饰器类 |
| 类型来源 | 生成器产出,全链路类型安全 | 类型推断,查询结果才有类型 |
| SQL 依赖 | 不熟 SQL 也能干活 | 接近 SQL,适合 SQL 高手 |
| 关系处理 | 嵌套读取、嵌套写入、隐式多对多 | 手动 join / relations 配置 |
两种路线没有绝对优劣:团队里 SQL 水平参差、看重协作和可维护性,选 schema-first;个人项目追求极致控制和最小开销,code-first 更顺手。迁移决策的前提是先想清楚这一点。
通用五步迁移流程
官方为每个 ORM 都准备了迁移指南,流程完全一致,共五步:
- 安装 Prisma CLI 与依赖
- 内省(Introspection)现有数据库
- 建立基线迁移(baseline)
- 安装并生成 Prisma Client
- 渐进替换查询,而非一次性重写
这套流程对 REST API、GraphQL API、任意应用形态都成立。
第一步到第三步:内省与基线
安装依赖(以 PostgreSQL 为例,其他数据库换对应驱动适配器):
npm install prisma @types/pg --save-dev
npm install @prisma/client @prisma/adapter-pg pg
初始化并连接现有数据库。Drizzle 与 Prisma 的连接字符串格式相同,已有的 DATABASE_URL 直接可用:
npx prisma init --output ../generated/prisma
npx prisma db pull
db pull 逆向数据库结构,生成模型定义。老库的表名、字段名会被原样搬进 Schema。想符合 Prisma 命名习惯(模型 PascalCase、字段 camelCase),用映射属性解耦,不改动数据库:
model Todo {
id Int @id
text String
done Boolean @default(false)
@@map("todo")
}
Note在 v7 中,
datasource块只留 provider,连接字符串配置在prisma.config.ts里通过env("DATABASE_URL")提供。
然后建立基线迁移。库已经存在,不能用 migrate dev 从头建,要生成一份描述现状的 SQL 并标记为「已应用」:
mkdir -p prisma/migrations/0_init
npx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
npx prisma migrate resolve --applied 0_init
从这之后,Prisma Migrate 就接管了 Schema 演进,以后改模型用 migrate dev 生成新迁移即可。
渐进替换查询
最后一步是替换代码。原则:先换读操作,再换写操作,一个模块一个模块来,Prisma 和其他 ORM 可以共存。以 Sequelize 为例的对照:
// Sequelize:查询
const users = await User.findAll({
where: { active: true },
limit: 10,
order: [["createdAt", "DESC"]],
});
// Prisma:同样的查询
const users = await prisma.user.findMany({
where: { active: true },
take: 10,
orderBy: { createdAt: "desc" },
});
创建带关联的记录,Prisma 的嵌套写入一步完成,其他 ORM 通常要两步:
// TypeORM:先建用户,再建文章
await connection.transaction(async (manager) => {
const user = manager.create(User, { name: "Alice" });
await manager.save(user);
const post = manager.create(Post, { title: "Hello", author: user });
await manager.save(post);
});
// Prisma:一个调用,自动事务
await prisma.user.create({
data: {
name: "Alice",
posts: { create: { title: "Hello" } },
},
});
Tip换写操作时注意差异:Drizzle 可以「原地取反」布尔字段(
not(todo.done)),Prisma 需要先findUnique再update;include与select不能同层混用,要嵌套使用。
从 Mongoose 迁移:注意版本边界
Mongoose 是 MongoDB 的 ODM。迁移流程相同(内省 → 生成 → 替换),但有一个必须提前知道的边界:
ImportantMongoDB 在 Prisma ORM v7 中尚不支持。官方建议 MongoDB 用户继续使用 Prisma ORM v6.19。本教程以 SQL 数据库为主线,MongoDB 相关迁移请留在 v6 路线执行。
另外 MongoDB 是「无 Schema」数据库,内省靠采样现有数据推断结构,所以迁移前要保证库里已有足够的数据样本。ObjectId 类型的引用关系需要手工整理成 @relation 关系字段,Mongoose 的 populate() 对应 Prisma 的 include。
迁移决策建议
综合官方对比与社区观点,给三类项目一个判断框架:
- 想迁移的:团队多人协作、类型安全诉求强、想统一迁移与查询工具链、现有 ORM 的关系处理让你反复写样板。Prisma 的生成类型和嵌套写入收益最明显。
- 谨慎的:重度依赖 SQL 方言特性(窗口函数、递归 CTE、复杂聚合)的项目,Prisma Client 表达不了的部分要落到
$queryRaw或 TypedSQL,先评估这部分占比。 - 不迁的:纯 SQL 查询构建器用得得心应手、性能敏感且每毫秒都要抠的极简项目,Drizzle/Knex 的低抽象层可能更合适。
迁移本身风险可控:内省和基线保证数据库不动,渐进替换保证随时可回退。真正的成本在团队学习曲线,而不是技术障碍。
参考来源
- Prisma 官方文档:switch-to-prisma-orm(from-drizzle / from-mongoose / from-sql-orms)
- Prisma 官方文档:Prisma vs Drizzle、Prisma vs TypeORM 对比页
- Better Stack:Drizzle vs Prisma、Knex vs Prisma