prisma-nestjs-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Prisma ORM + NestJS — Patrones de Producción

Prisma ORM + NestJS — 生产级集成模式

Guía completa de integración Prisma con NestJS siguiendo Clean Architecture. Cubre desde la configuración base hasta transacciones atómicas críticas, repositorios, optimización de queries y testing.
遵循整洁架构的Prisma与NestJS完整集成指南,覆盖从基础配置到关键原子事务、仓储层、查询优化以及测试的全流程内容。

Referencias disponibles

可用参考文档

Lee el archivo correspondiente cuando necesites profundidad en un área específica:
  • references/setup-and-service.md
    — Instalación, PrismaService, módulo global, health check
  • references/schema-and-migrations.md
    — Schema design, tipos, relaciones, índices, migraciones
  • references/repository-pattern.md
    — Repositorios como adaptadores de infraestructura (Clean Architecture)
  • references/transactions.md
    — Transacciones atómicas, SELECT FOR UPDATE, manejo de concurrencia
  • references/query-patterns.md
    — N+1 prevention, include/select, paginación, queries complejas
  • references/testing.md
    — Testing con jest-mock-extended, prisma-mock, integración con testcontainers

如需深入了解特定领域的内容,请阅读对应的文档:
  • references/setup-and-service.md
    — 安装、PrismaService、全局模块、健康检查
  • references/schema-and-migrations.md
    — Schema设计、类型、关联关系、索引、数据迁移
  • references/repository-pattern.md
    — 作为基础设施适配器的仓储层(整洁架构)
  • references/transactions.md
    — 原子事务、SELECT FOR UPDATE、并发处理
  • references/query-patterns.md
    — N+1问题预防、include/select、分页、复杂查询
  • references/testing.md
    — 使用jest-mock-extended、prisma-mock进行测试,与testcontainers集成

Cuándo usar cada referencia

各参考文档适用场景

TareaReferencia
Configurar Prisma por primera vez en NestJS
setup-and-service.md
Diseñar o modificar el schema, crear migraciones
schema-and-migrations.md
Crear repositorios para un módulo de dominio
repository-pattern.md
Reservas, locks, operaciones concurrentes
transactions.md
Optimizar queries lentas, eliminar N+1
query-patterns.md
Mockear Prisma en tests unitarios/integración
testing.md

任务参考文档
首次在NestJS中配置Prisma
setup-and-service.md
设计或修改schema、创建数据迁移
schema-and-migrations.md
为领域模块创建仓储层
repository-pattern.md
预订、锁、并发操作
transactions.md
优化慢查询、解决N+1问题
query-patterns.md
在单元/集成测试中Mock Prisma
testing.md

Reglas críticas (siempre en contexto)

关键规则(请始终结合上下文遵循)

1. PrismaService es global, nunca instanciar PrismaClient directamente

1. PrismaService是全局的,永远不要直接实例化PrismaClient

typescript
// ❌ Nunca
const prisma = new PrismaClient();

// ✅ Siempre via inyección de dependencias
constructor(private readonly prisma: PrismaService) {}
typescript
// ❌ 禁止这么做
const prisma = new PrismaClient();

// ✅ 始终通过依赖注入使用
constructor(private readonly prisma: PrismaService) {}

2. Transacciones atómicas para operaciones de escritura compuestas

2. 复合写入操作必须使用原子事务

typescript
// ✅ Patrón correcto para cualquier operación que modifique >1 tabla
await this.prisma.$transaction(async (tx) => {
  const gift = await tx.gift.findUnique({ where: { id: giftId } });
  if (gift.status !== 'AVAILABLE') throw new ConflictException();
  await tx.gift.update({ where: { id: giftId }, data: { status: 'RESERVED' } });
  await tx.reservation.create({ data: { giftId, reservedById: userId } });
});
typescript
// ✅ 适用于所有修改超过1张表的操作的正确模式
await this.prisma.$transaction(async (tx) => {
  const gift = await tx.gift.findUnique({ where: { id: giftId } });
  if (gift.status !== 'AVAILABLE') throw new ConflictException();
  await tx.gift.update({ where: { id: giftId }, data: { status: 'RESERVED' } });
  await tx.reservation.create({ data: { giftId, reservedById: userId } });
});

3. Repositorios en la capa de infraestructura, nunca en controllers ni services de dominio

3. 仓储层放在基础设施层,永远不要出现在控制器或领域服务中

typescript
// La interfaz vive en el dominio
export interface ReservationRepository {
  findActiveByGiftId(giftId: string): Promise<Reservation | null>;
  create(data: CreateReservationData): Promise<Reservation>;
}

// La implementación Prisma vive en infraestructura
@Injectable()
export class PrismaReservationRepository implements ReservationRepository { ... }
typescript
// 接口定义在领域层
export interface ReservationRepository {
  findActiveByGiftId(giftId: string): Promise<Reservation | null>;
  create(data: CreateReservationData): Promise<Reservation>;
}

// Prisma实现放在基础设施层
@Injectable()
export class PrismaReservationRepository implements ReservationRepository { ... }

4. Nunca exponer el PrismaClient fuera del módulo de infraestructura

4. 永远不要将PrismaClient暴露到基础设施模块之外

Los módulos de dominio y aplicación trabajan contra interfaces, no contra Prisma directamente.
领域和应用层模块仅面向接口开发,不直接依赖Prisma。

5. Siempre usar
select
o
include
explícito — nunca retornar el modelo completo

5. 始终显式使用
select
include
—— 永远不要返回完整模型

typescript
// ❌ Retorna passwordHash, campos internos
return this.prisma.user.findUnique({ where: { id } });

// ✅ Solo los campos necesarios
return this.prisma.user.findUnique({
  where: { id },
  select: { id: true, nombre: true, email: true, createdAt: true }
});

typescript
// ❌ 会返回passwordHash等内部字段
return this.prisma.user.findUnique({ where: { id } });

// ✅ 仅返回所需字段
return this.prisma.user.findUnique({
  where: { id },
  select: { id: true, nombre: true, email: true, createdAt: true }
});

Fuentes y documentación oficial

来源与官方文档