惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
The GitHub Blog
The GitHub Blog
Recent Announcements
Recent Announcements
MyScale Blog
MyScale Blog
P
Proofpoint News Feed
S
Security @ Cisco Blogs
N
News and Events Feed by Topic
H
Hacker News: Front Page
Attack and Defense Labs
Attack and Defense Labs
S
Secure Thoughts
Microsoft Security Blog
Microsoft Security Blog
N
Netflix TechBlog - Medium
U
Unit 42
Stack Overflow Blog
Stack Overflow Blog
T
Threat Research - Cisco Blogs
Google Online Security Blog
Google Online Security Blog
Spread Privacy
Spread Privacy
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
L
LINUX DO - 热门话题
T
Tenable Blog
博客园 - 叶小钗
D
DataBreaches.Net
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园_首页
人人都是产品经理
人人都是产品经理
aimingoo的专栏
aimingoo的专栏
C
Check Point Blog
博客园 - 三生石上(FineUI控件)
量子位
P
Proofpoint News Feed
H
Help Net Security
Blog — PlanetScale
Blog — PlanetScale
宝玉的分享
宝玉的分享
Recorded Future
Recorded Future
The Register - Security
The Register - Security
F
Fortinet All Blogs
Engineering at Meta
Engineering at Meta
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Last Week in AI
Last Week in AI
S
Schneier on Security
V
Vulnerabilities – Threatpost
雷峰网
雷峰网
Microsoft Azure Blog
Microsoft Azure Blog
G
GRAHAM CLULEY
G
Google Developers Blog
月光博客
月光博客
V
V2EX
T
Troy Hunt's Blog
A
Arctic Wolf

博客园 - 丁少华

React UI 库推荐 Loop Engineering Vue 3 UI 组件库 Neon白嫖免费pgsql 域名利用cloudflare免费图床 nginx反代CloudflarePages提示502 vite使用shadcn vite使用biome Window下Nginx winserver2022安装不上软件 mac已损坏无法打开 代码高亮 命令运行器之task 命令运行器之just windows开启wsl 白嫖Redis 白嫖MongoDB vercel无服务函数 无服务器函数完全指南 在线 mock 方案 解释型语言和编译型语言 何时该使用monorepo monorepo前端专属吗 Cursor锁区问题 CentOS9上Let’s Encrypt自动续签 Windows给文件夹别名 ai 常识 nestjs的orm之Prisma
nestjs逆向工程Prisma与DTO
丁少华 · 2025-11-18 · via 博客园 - 丁少华

前沿

在nestjs中虽然官方推荐是 TypeORM,但是最佳实践仍然是 Prisma。
虽然使用Prisma 你可以不用定义任何实体模型,但是最好还是定义。
以下说明原因!

1. 为什么可以省略 DTO?

技术上完全可以,因为:

  • TypeScript 工具类型:可以用 OmitPick 等从 Prisma 类型中排除敏感字段
  • 类型安全:Prisma 生成的类型已经提供了基础类型检查
  • 减少代码量:少写一层抽象,更直接简单
// 完全可以这样用,不用自定义 DTO
@Post()
createUser(@Body() userInput: Omit<Prisma.UserCreateInput, 'id' | 'salt' | 'createdAt'>) {
  // 业务处理...
}

2. 为什么又建议定义 DTO?

为了更好的工程实践

🔒 安全性

// 自定义 DTO 明确指定客户端能传什么
export class CreateUserDto {
  @IsEmail()
  email: string;
  
  @MinLength(6)  // Prisma 类型没有这个!
  password: string;
}

📋 输入验证

// Prisma 类型只有基础类型,没有业务规则
export type UserCreateInput = {
  email: string;     // 任何字符串都行,包括 "invalid-email"
  password: string;  // 包括 "123" 这种弱密码
};

// DTO 有业务级验证
export class CreateUserDto {
  @IsEmail()        // 必须是邮箱格式
  email: string;
  
  @MinLength(6)     // 至少6位
  password: string;
}

📚 API 文档

// Swagger 装饰器生成文档
export class CreateUserDto {
  @ApiProperty({ description: '用户邮箱', example: 'user@example.com' })
  @IsEmail()
  email: string;
}

🎯 明确的接口契约

DTO 定义了前端与后端的明确约定,不受数据库 schema 变更的影响。

3. DTO 如何结合 Prisma 类型

最佳实践:继承 + 扩展

// 实现 Prisma 类型,添加验证和文档
export class CreateUserDto implements Pick<Prisma.UserCreateInput, 'email' | 'username'> {
  @ApiProperty()
  @IsEmail()
  email: string;

  @ApiProperty()
  @MinLength(3)
  username: string;

  @ApiProperty()
  @MinLength(6)
  password: string; // 额外字段,Prisma 类型中没有的验证规则
}

4. Entities 的本质与省略

Entities 的本质

// Entity 就是数据库所有字段的映射
export class UserEntity {
  id: number;
  email: string;
  password: string;
  salt: string;
  createdAt: Date;
  // ... 所有数据库字段
}

什么时候可以省略 Entities?

在以下情况下可以安全省略

  • ✅ 使用 Prisma 等现代 ORM
  • ✅ 主要是简单的 CRUD 操作
  • ✅ 没有复杂的业务逻辑封装需求
  • ✅ 业务逻辑直接在 Service 层处理
// 现代做法:Prisma 类型 + DTO,跳过 Entity 层
@Injectable()
export class UserService {
  async create(dto: CreateUserDto): Promise<UserResponseDto> {
    // 直接使用 Prisma,不需要 Entity 转换层
    const user = await this.prisma.user.create({
      data: {
        email: dto.email,
        password: await this.hashPassword(dto.password),
        // ... 其他字段
      }
    });
    
    return this.toResponseDto(user);
  }
}

总结

DTO 可以,但不推荐 建议使用,为了验证、安全和文档 Entities 大多数情况可以 可以省略,除非需要复杂业务逻辑封装
组件 是否可以省略 建议

现代 NestJS + Prisma 推荐架构

Controller (DTO 输入输出) 
↓  
Service (业务逻辑,直接使用 Prisma 类型)
↓  
Prisma (数据库操作)

这样既保持了类型安全,又减少了不必要的抽象层次。

补充

DTO 的命名有一套常见的约定,我来为你总结

// create-user.dto.ts
export class CreateUserDto {
  @ApiProperty()
  @IsEmail()
  email: string;

  @ApiProperty()
  @MinLength(6)
  password: string;

  @ApiProperty()
  @IsString()
  username: string;
}

// update-user.dto.ts  
export class UpdateUserDto {
  @ApiPropertyOptional()
  @IsOptional()
  @IsEmail()
  email?: string;

  @ApiPropertyOptional()
  @IsOptional()
  @IsString()
  username?: string;

  @ApiPropertyOptional()
  @IsOptional()
  @IsString()
  nickname?: string;
}

// find-users.dto.ts
export class FindUsersDto {
  @ApiPropertyOptional()
  @IsOptional()
  @IsNumber()
  page?: number = 1;

  @ApiPropertyOptional() 
  @IsOptional()
  @IsNumber()
  limit?: number = 10;

  @ApiPropertyOptional()
  @IsOptional()
  @IsString()
  search?: string;
}

// user-response.dto.ts
export class UserResponseDto {
  @ApiProperty()
  id: number;

  @ApiProperty()
  email: string;

  @ApiProperty()
  username: string;

  @ApiProperty()
  createdAt: Date;
}