创建日期:2026-09-08 | 最近更新:2026-09-08 生态版本(2026-09 npm 核对):TypeORM 1.x /
@nestjs/typeorm12、@prisma/client7.x / Prisma CLI。本文无数据库环境,代码未在本机运行;接线形态为官方长期稳定的写法,以各自官方文档为准。
数据层:TypeORM 与 Prisma,怎么选、怎么接进 Nest
一句话:Nest 不管你怎么连数据库,它只负责把「数据访问对象」变成可注入的 provider。TypeORM 和 Prisma 是两种哲学:TypeORM 从实体代码出发生成表(code-first,装饰器满天飞),Prisma 从 schema 出发生成类型安全的客户端(schema-first)。选型基本是「装饰器 ORM」vs「schema-first + 生成器」之争,不是对错之分。
1. 先分清两种范式
| TypeORM | Prisma | |
|---|---|---|
| 出发点 | 用 TS 装饰器定义实体,代码即模型 | 用 schema.prisma 定义模型,生成类型安全客户端 |
| 迁移 | typeorm migration(需自建/同步) | prisma migrate(schema 即真相,强迁移工作流) |
| 查询体验 | Repository/QueryBuilder,接近手写 SQL 的 ORM | Prisma Client:全类型安全、自动提示字段、防 typo |
| 关系加载 | 需显式 relations / 注意 N+1 | include/select 显式、结果强类型 |
| 与 Nest 集成 | @nestjs/typeorm(forRoot + Repository 注入) | 自写 PrismaService(一层薄封装) |
| 学习曲线 | ORM 概念多(Entity/Repository/DataSource) | schema 学习点集中、Client 上手快 |
给个人的建议:
- 想要「ORM 自由度 + 熟悉 SQL/ActiveRecord 思路」→ TypeORM;
- 想要「schema 单一事实来源 + 类型安全到爆 + 不想记装饰器」→ Prisma(近年新项目增长明显);
- 团队已有 DB 领域模型要强约束 → Prisma 的 migrate + 生成更省心。
2. TypeORM 接进 Nest
接线(app.module)
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Cat } from './cats/cat.entity.js';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres', // / mysql / sqlite ...
host: process.env.DB_HOST,
port: Number(process.env.DB_PORT),
username: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
autoLoadEntities: true, // 由 forFeature 自动收集实体
synchronize: false, // 生产务必 false,用 migration
}),
],
})
export class AppModule {}
特性模块:Repository 注入
// cats.module.ts
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [TypeOrmModule.forFeature([Cat])], // 给本模块注册 Cat 的 Repository
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {}
// cats.service.ts —— 构造器直接拿到类型化 Repository
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Cat } from './cat.entity.js';
@Injectable()
export class CatsService {
constructor(
@InjectRepository(Cat)
private readonly catRepo: Repository<Cat>,
) {}
findAll() { return this.catRepo.find(); }
create(data: Partial<Cat>) { return this.catRepo.save(this.catRepo.create(data)); }
}
看懂了吗:
@nestjs/typeorm做的就是把 TypeORM 的 Repository 变成可注入 provider——剩下的全是 TypeORM 自己的 API(.find/.save/.createQueryBuilder/…)。这也是「Nest 只负责接,数据层由你选」的体现。
事务 / 多写一致
async transfer() {
await this.dataSource.transaction(async (manager) => {
await manager.save(...);
await manager.save(...); // 任一失败 → 整体回滚
});
}
3. Prisma 接进 Nest
schema 定义 + 生成
// prisma/schema.prisma
generator client { provider = "prisma-client-js" }
datasource db { provider = "postgresql"; url = env("DATABASE_URL") }
model Cat {
id Int @id @default(autoincrement())
name String
age Int
breed String?
}
npx prisma migrate dev --name init # 生成迁移 + 应用 + 重新生成 client
薄封装 PrismaService(官网推荐姿势)
// prisma/prisma.service.ts
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
@Injectable()
export class PrismaService extends PrismaClient
implements OnModuleInit, OnModuleDestroy {
async onModuleInit() { await this.$connect(); } // 启动连库(呼应篇1生命周期)
async onModuleDestroy() { await this.$disconnect(); } // 优雅断开
}
// cats.service.ts —— 直接用 PrismaClient,类型安全到字段级
@Injectable()
export class CatsService {
constructor(private readonly prisma: PrismaService) {}
findAll() { return this.prisma.cat.findMany({ include: { owner: true } }); }
create(data: CreateCatDto) { return this.prisma.cat.create({ data }); }
}
对比 TypeORM 的
@InjectRepository,Prisma 是一个PrismaService管全部模型(prisma.cat / prisma.user / …),不需要 per-entity 注册。想限制只能访问部分表,可再按域包 Service。
4. 绕不开的坑(两种都适用)
- N+1 查询:TypeORM 默认不加载关联(要
relations),Prisma 不include就没有——但循环里逐条查关联就是 N+1。列表接口要么预加载关联、要么用查询构建器/批量include。 - 不要把
synchronize: true带进生产(TypeORM)——改实体自动改表结构,重则丢数据。上migration。 - 类型别用
any:DTO → 实体/Client 的参数要过校验(下篇 ValidationPipe 就是干这个的),否则脏数据直接进库。 - 连接生命周期:接进 Nest 就一定要在
onModuleInit/$connect+ 销毁钩子断开(PrismaService 已示范),别把连接建在模块顶层。 - 事务边界别跨 service 乱开:能收进一个事务函数就收,宁可参数传 manager,也别各开各的连接。
5. 怎么选(决策清单)
| 你的情况 | 倾向 |
|---|---|
| 老项目已有 TypeORM / 熟悉装饰器 ORM | 继续 TypeORM |
| 从零起步、想要强类型 + 省心迁移 | Prisma |
| 大量复杂原生 SQL / 性能要手控 | 两者都可下探到 raw SQL;TypeORM 的 QueryBuilder 或 prisma.$queryRaw |
| 跟 Nest 生态贴最紧 | TypeORM 有官方 @nestjs/typeorm 一键;Prisma 是官方文档里同等推荐的一等公民 |
提醒:TypeORM 版本跨度大(0.3 → 1.x 有破坏性差异)、Prisma 大版本也不断(7.x 已常见)。别背教程里的旧 API,写前打开你
node_modules里对应版本的文档。
关联
- 上一篇:模块化与 Provider 作用域
- 下一篇:DTO / ValidationPipe:把参数校验做成规范(数据进门的第一道闸)
- 参考:TypeORM + Nest、Prisma + Nest