{T}

NestJS业务逻辑层与Prisma详解

学习目标:理解业务逻辑层架构、掌握 Controller 参数传递、熟练使用 Prisma Client 的 CRUD API。


一、业务逻辑层架构流程

1.1 完整的请求处理流程

code
前端请求
    ↓
Controller(控制器层)
    ↓ 参数解析
Service(业务逻辑层)
    ↓ 数据操作
Prisma Client(ORM 层)
    ↓ SQL 生成
Database(数据库层)
    ↓ 数据返回
Prisma Client
    ↓ 对象映射
Service
    ↓ 数据处理
Controller
    ↓ 响应封装
前端响应

1.2 各层职责详解

层级职责关键内容
Controller接收请求、参数解析、响应封装获取请求参数、调用 Service、返回数据
Service业务逻辑处理、数据转换实现具体业务逻辑、调用 Prisma
PrismaORM 操作、SQL 生成数据库 CRUD 操作、对象映射
Database数据持久化、数据查询数据存储、事务处理

1.3 参数传递流程

code
Controller 层:
│
├── 获取请求参数
│   ├── @Query() - 查询参数
│   ├── @Param() - 路径参数
│   ├── @Body() - 请求体参数
│   └── @Headers() - 请求头参数
│
├── 调用 Service 方法
│   └── this.homeService.create(createDto)
│
└── 返回响应
    └── return result

Service 层:
│
├── 接收 Controller 传递的参数
│   └── async create(createDto: CreateHomeResourceDto)
│
├── 调用 Prisma 操作数据库
│   └── return this.prisma.homeResources.create({ data: createDto })
│
└── 返回数据给 Controller
    └── return result

二、Controller 参数获取方式

2.1 不同 HTTP 方法的参数获取

code
HTTP 方法与参数类型:
│
├── GET 请求
│   ├── 主要参数:@Query() 查询参数
│   ├── 示例:GET /home-resources?page=1&limit=10
│   └── 使用场景:查询列表、过滤、分页
│
├── POST 请求
│   ├── 主要参数:@Body() 请求体参数
│   ├── 示例:POST /home-resources { "title": "xxx" }
│   └── 使用场景:创建资源
│
├── PUT 请求
│   ├── 主要参数:@Body() 请求体参数 + @Param() 路径参数
│   ├── 示例:PUT /home-resources/1 { "title": "xxx" }
│   └── 使用场景:整体更新资源
│
├── PATCH 请求
│   ├── 主要参数:@Body() 请求体参数 + @Param() 路径参数
│   ├── 示例:PATCH /home-resources/1 { "title": "xxx" }
│   └── 使用场景:部分更新资源
│
└── DELETE 请求
    ├── 主要参数:@Param() 路径参数
    ├── 示例:DELETE /home-resources/1
    └── 使用场景:删除资源

2.2 参数组合使用

常见组合方式

typescript
// 1. POST + 路径参数 + Body 参数
@Post(':id/comments')
async addComment(
  @Param('id') id: string,
  @Body() createCommentDto: CreateCommentDto,
) {
  return this.service.addComment(+id, createCommentDto);
}

// 2. GET + 路径参数 + Query 参数
@Get(':id/posts')
async getUserPosts(
  @Param('id') id: string,
  @Query('page') page: number,
  @Query('limit') limit: number,
) {
  return this.service.getUserPosts(+id, page, limit);
}

// 3. PUT + 路径参数 + Body 参数
@Put(':id')
async update(
  @Param('id') id: string,
  @Body() updateDto: UpdateDto,
) {
  return this.service.update(+id, updateDto);
}

2.3 参数传递到 Service 层

Controller 层

typescript
@Controller('home')
export class HomeController {
  constructor(private readonly homeService: HomeService) {}

  // GET 查询列表
  @Get()
  async findAll(
    @Query('page') page: number = 1,
    @Query('limit') limit: number = 10,
  ) {
    return this.homeService.findAll(page, limit);
  }

  // GET 查询单条
  @Get(':id')
  async findOne(@Param('id') id: string) {
    return this.homeService.findOne(+id);
  }

  // POST 创建
  @Post()
  async create(@Body() createDto: CreateHomeResourceDto) {
    return this.homeService.create(createDto);
  }

  // PUT 更新
  @Put(':id')
  async update(
    @Param('id') id: string,
    @Body() updateDto: UpdateHomeResourceDto,
  ) {
    return this.homeService.update(+id, updateDto);
  }

  // DELETE 删除
  @Delete(':id')
  async remove(@Param('id') id: string) {
    return this.homeService.remove(+id);
  }
}

Service 层

typescript
@Injectable()
export class HomeService {
  constructor(private prisma: PrismaService) {}

  // 查询列表
  async findAll(page: number, limit: number) {
    const skip = (page - 1) * limit;
    return this.prisma.homeResources.findMany({
      skip,
      take: limit,
      orderBy: { order: 'asc' },
    });
  }

  // 查询单条
  async findOne(id: number) {
    return this.prisma.homeResources.findUnique({
      where: { id },
    });
  }

  // 创建
  async create(createDto: CreateHomeResourceDto) {
    return this.prisma.homeResources.create({
      data: createDto,
    });
  }

  // 更新
  async update(id: number, updateDto: UpdateHomeResourceDto) {
    return this.prisma.homeResources.update({
      where: { id },
      data: updateDto,
    });
  }

  // 删除
  async remove(id: number) {
    return this.prisma.homeResources.delete({
      where: { id },
    });
  }
}

三、Prisma Client CRUD API 详解

3.1 Prisma API 总览

code
Prisma Client API 分类:
│
├── 查询操作(Read)
│   ├── findMany()        # 查询多条记录
│   ├── findFirst()       # 查询第一条记录
│   ├── findUnique()      # 查询唯一记录(基于唯一字段)
│   ├── findFirstOrThrow()  # 查询第一条或抛异常
│   └── findUniqueOrThrow() # 查询唯一记录或抛异常
│
├── 创建操作(Create)
│   ├── create()          # 创建单条记录
│   └── createMany()      # 批量创建记录
│
├── 更新操作(Update)
│   ├── update()          # 更新单条记录
│   ├── updateMany()      # 批量更新记录
│   └── upsert()          # 更新或创建
│
├── 删除操作(Delete)
│   ├── delete()          # 删除单条记录
│   └── deleteMany()      # 批量删除记录
│
└── 计数操作(Count)
    └── count()           # 统计记录数

3.2 查询操作详解

3.2.1 findMany - 查询多条记录

基本用法

typescript
// 查询所有记录
const allUsers = await prisma.user.findMany();

// 带条件查询
const activeUsers = await prisma.user.findMany({
  where: {
    status: 'active',
  },
});

// 分页查询
const users = await prisma.user.findMany({
  skip: 0,    // 跳过多少条
  take: 10,   // 获取多少条
});

// 排序查询
const users = await prisma.user.findMany({
  orderBy: {
    createdAt: 'desc',
  },
});

// 选择字段
const users = await prisma.user.findMany({
  select: {
    id: true,
    name: true,
    email: true,
  },
});

// 组合查询
const users = await prisma.user.findMany({
  where: {
    status: 'active',
    age: {
      gte: 18,  // age >= 18
    },
  },
  skip: 0,
  take: 10,
  orderBy: {
    createdAt: 'desc',
  },
  select: {
    id: true,
    name: true,
    email: true,
  },
});

查询条件操作符

操作符说明示例
equals等于{ status: { equals: 'active' } }
not不等于{ status: { not: 'inactive' } }
in在列表中{ id: { in: [1, 2, 3] } }
notIn不在列表中{ id: { notIn: [1, 2, 3] } }
lt小于{ age: { lt: 18 } }
lte小于等于{ age: { lte: 18 } }
gt大于{ age: { gt: 18 } }
gte大于等于{ age: { gte: 18 } }
contains包含{ name: { contains: 'Tom' } }
startsWith以...开头{ name: { startsWith: 'T' } }
endsWith以...结尾{ email: { endsWith: '@gmail.com' } }

3.2.2 findFirst - 查询第一条记录

基本用法

typescript
// 查询第一条记录
const firstUser = await prisma.user.findFirst();

// 查询符合条件的第一条记录
const firstActiveUser = await prisma.user.findFirst({
  where: {
    status: 'active',
  },
});

// 查询并排序
const latestUser = await prisma.user.findFirst({
  orderBy: {
    createdAt: 'desc',
  },
});

// 查询年龄最大的用户
const oldestUser = await prisma.user.findFirst({
  orderBy: {
    age: 'desc',
  },
});

3.2.3 findUnique - 查询唯一记录

适用场景

  • 查询主键(ID)
  • 查询唯一字段(设置了 @unique 的字段)

基本用法

typescript
// 根据 ID 查询
const user = await prisma.user.findUnique({
  where: {
    id: 1,
  },
});

// 根据唯一字段查询
const user = await prisma.user.findUnique({
  where: {
    email: 'tom@example.com',
  },
});

// 根据唯一字段组合查询(联合唯一索引)
const user = await prisma.user.findUnique({
  where: {
    email_phone: {
      email: 'tom@example.com',
      phone: '1234567890',
    },
  },
});

Schema 定义唯一字段

prisma
model User {
  id       Int    @id @default(autoincrement())
  email    String @unique    // 唯一字段
  phone    String @unique    // 唯一字段
  username String @unique    // 唯一字段

  // 联合唯一索引
  @@unique([email, phone], name: "email_phone")
}

返回值说明

  • 找到记录:返回对象
  • 未找到记录:返回 null

3.2.4 findFirstOrThrow 和 findUniqueOrThrow

与 findFirst 和 findUnique 的区别

方法找到记录未找到记录
findFirst()返回对象返回 null
findFirstOrThrow()返回对象抛出异常
findUnique()返回对象返回 null
findUniqueOrThrow()返回对象抛出异常

使用场景

typescript
// 使用 findUniqueOrThrow 查询用户,不存在则抛异常
const user = await prisma.user.findUniqueOrThrow({
  where: { id: 1 },
});

// 配合 try-catch 处理
try {
  const user = await prisma.user.findUniqueOrThrow({
    where: { id: 999 },
  });
  return user;
} catch (error) {
  throw new NotFoundException('用户不存在');
}

异常类型

  • PrismaClientKnownRequestError
  • 错误代码:P2025(记录不存在)

3.3 创建操作详解

3.3.1 create - 创建单条记录

基本用法

typescript
// 创建用户
const user = await prisma.user.create({
  data: {
    name: 'Tom',
    email: 'tom@example.com',
    age: 25,
  },
});

// 创建并返回指定字段
const user = await prisma.user.create({
  data: {
    name: 'Tom',
    email: 'tom@example.com',
  },
  select: {
    id: true,
    name: true,
    email: true,
  },
});

3.3.2 createMany - 批量创建记录

基本用法

typescript
// 批量创建
const result = await prisma.user.createMany({
  data: [
    { name: 'Tom', email: 'tom@example.com' },
    { name: 'Jerry', email: 'jerry@example.com' },
    { name: 'Alice', email: 'alice@example.com' },
  ],
});

// 返回值:{ count: 3 }  创建的记录数

参数说明

typescript
interface CreateManyOptions {
  data: Array<any>;              // 要创建的数据数组
  skipDuplicates?: boolean;      // 是否跳过重复记录(默认 false)
}

3.4 更新操作详解

3.4.1 update - 更新单条记录

基本用法

typescript
// 更新用户
const user = await prisma.user.update({
  where: { id: 1 },
  data: {
    name: 'Tom Updated',
    age: 26,
  },
});

// 更新并返回指定字段
const user = await prisma.user.update({
  where: { id: 1 },
  data: {
    name: 'Tom Updated',
  },
  select: {
    id: true,
    name: true,
  },
});

更新操作符

typescript
// 数字字段增加
await prisma.user.update({
  where: { id: 1 },
  data: {
    age: {
      increment: 1,  // age = age + 1
    },
  },
});

// 数字字段减少
await prisma.user.update({
  where: { id: 1 },
  data: {
    age: {
      decrement: 1,  // age = age - 1
    },
  },
});

// 数字字段乘法
await prisma.user.update({
  where: { id: 1 },
  data: {
    age: {
      multiply: 2,  // age = age * 2
    },
  },
});

// 设置字段值
await prisma.user.update({
  where: { id: 1 },
  data: {
    name: {
      set: 'New Name',  // name = 'New Name'
    },
  },
});

3.4.2 updateMany - 批量更新记录

基本用法

typescript
// 批量更新
const result = await prisma.user.updateMany({
  where: {
    status: 'pending',
  },
  data: {
    status: 'active',
  },
});

// 返回值:{ count: 5 }  更新的记录数

3.4.3 upsert - 更新或创建

upsert() 的作用

  • 如果记录存在,则更新
  • 如果记录不存在,则创建

基本用法

typescript
const user = await prisma.user.upsert({
  where: { email: 'tom@example.com' },
  update: {
    name: 'Tom Updated',
    age: 26,
  },
  create: {
    email: 'tom@example.com',
    name: 'Tom',
    age: 25,
  },
});

参数说明

typescript
interface UpsertOptions {
  where: { ... };        // 查询条件(必传)
  update: { ... };       // 更新数据(必传)
  create: { ... };       // 创建数据(必传)
  select?: { ... };      // 选择返回字段(可选)
  include?: { ... };     // 关联查询(可选)
}

upsert() 执行逻辑

code
upsert 执行流程:
│
├── 第一步:根据 where 条件查询记录
│
├── 第二步:判断记录是否存在
│   ├── 存在 → 执行 update 操作
│   └── 不存在 → 执行 create 操作
│
└── 第三步:返回操作后的记录

使用场景

typescript
// 场景 1:用户首次登录或更新信息
const user = await prisma.user.upsert({
  where: { email: 'tom@example.com' },
  update: {
    lastLoginAt: new Date(),
  },
  create: {
    email: 'tom@example.com',
    name: 'Tom',
    lastLoginAt: new Date(),
  },
});

// 场景 2:商品浏览次数或创建浏览记录
const view = await prisma.productView.upsert({
  where: {
    productId_userId: {
      productId: 1,
      userId: 1,
    },
  },
  update: {
    viewCount: {
      increment: 1,
    },
  },
  create: {
    productId: 1,
    userId: 1,
    viewCount: 1,
  },
});

3.5 删除操作详解

3.5.1 delete - 删除单条记录

基本用法

typescript
// 删除用户
const user = await prisma.user.delete({
  where: { id: 1 },
});

// 删除并返回指定字段
const user = await prisma.user.delete({
  where: { id: 1 },
  select: {
    id: true,
    name: true,
  },
});

注意

  • 如果记录不存在,会抛出异常
  • 如果有外键约束,需要先删除关联记录

3.5.2 deleteMany - 批量删除记录

基本用法

typescript
// 删除所有符合条件的记录
const result = await prisma.user.deleteMany({
  where: {
    status: 'inactive',
  },
});

// 返回值:{ count: 5 }  删除的记录数

// 删除所有记录(危险操作)
const result = await prisma.user.deleteMany();

3.6 计数操作

count() - 统计记录数

typescript
// 统计所有记录
const count = await prisma.user.count();
// 返回值:{ count: 100 }

// 统计符合条件的记录
const activeCount = await prisma.user.count({
  where: {
    status: 'active',
  },
});

四、Prisma API 对比总结

4.1 查询方法对比

方法返回值记录不存在使用场景
findMany()数组返回 []查询列表
findFirst()对象或 null返回 null查询第一条
findUnique()对象或 null返回 null查询唯一记录
findFirstOrThrow()对象抛异常查询第一条或报错
findUniqueOrThrow()对象抛异常查询唯一记录或报错

4.2 CRUD 方法对比

方法单条/批量返回值说明
create()单条创建的对象创建一条记录
createMany()批量{ count: number }批量创建
update()单条更新后的对象更新一条记录
updateMany()批量{ count: number }批量更新
upsert()单条创建或更新后的对象更新或创建
delete()单条删除的对象删除一条记录
deleteMany()批量{ count: number }批量删除

4.3 Prisma API 最佳实践

1. 选择合适的查询方法

typescript
//  不推荐:使用 findMany 查询单条
const users = await prisma.user.findMany({
  where: { id: 1 },
  take: 1,
});

//  推荐:使用 findUnique 查询单条
const user = await prisma.user.findUnique({
  where: { id: 1 },
});

2. 使用 findUniqueOrThrow 处理不存在的情况

typescript
//  不推荐:手动判断 null
const user = await prisma.user.findUnique({ where: { id: 1 } });
if (!user) {
  throw new NotFoundException('用户不存在');
}

//  推荐:使用 findUniqueOrThrow
try {
  const user = await prisma.user.findUniqueOrThrow({ where: { id: 1 } });
  return user;
} catch (error) {
  throw new NotFoundException('用户不存在');
}

3. 使用 select 优化查询性能

typescript
//  不推荐:查询所有字段
const users = await prisma.user.findMany();

//  推荐:只查询需要的字段
const users = await prisma.user.findMany({
  select: {
    id: true,
    name: true,
    email: true,
  },
});

4. 使用 upsert 简化逻辑

typescript
//  不推荐:先查询再判断
const user = await prisma.user.findUnique({ where: { email } });
if (user) {
  await prisma.user.update({
    where: { email },
    data: { lastLoginAt: new Date() },
  });
} else {
  await prisma.user.create({
    data: { email, lastLoginAt: new Date() },
  });
}

//  推荐:使用 upsert
const user = await prisma.user.upsert({
  where: { email },
  update: { lastLoginAt: new Date() },
  create: { email, lastLoginAt: new Date() },
});

五、完整实战示例

5.1 完整的 Service 实现

typescript
// src/modules/home/home.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import { CreateHomeResourceDto } from './dto/create-home-resource.dto';
import { UpdateHomeResourceDto } from './dto/update-home-resource.dto';

@Injectable()
export class HomeService {
  constructor(private prisma: PrismaService) {}

  // 查询列表(分页)
  async findAll(page: number = 1, limit: number = 10) {
    const skip = (page - 1) * limit;
    const [data, total] = await Promise.all([
      this.prisma.homeResources.findMany({
        skip,
        take: limit,
        orderBy: { order: 'asc' },
      }),
      this.prisma.homeResources.count(),
    ]);

    return {
      data,
      meta: {
        total,
        page,
        limit,
        totalPages: Math.ceil(total / limit),
      },
    };
  }

  // 查询单条
  async findOne(id: number) {
    const resource = await this.prisma.homeResources.findUnique({
      where: { id },
    });

    if (!resource) {
      throw new NotFoundException('资源不存在');
    }

    return resource;
  }

  // 创建
  async create(createDto: CreateHomeResourceDto) {
    return this.prisma.homeResources.create({
      data: createDto,
    });
  }

  // 更新
  async update(id: number, updateDto: UpdateHomeResourceDto) {
    // 先检查是否存在
    await this.findOne(id);

    return this.prisma.homeResources.update({
      where: { id },
      data: updateDto,
    });
  }

  // 删除
  async remove(id: number) {
    // 先检查是否存在
    await this.findOne(id);

    return this.prisma.homeResources.delete({
      where: { id },
    });
  }

  // 批量更新排序
  async updateOrder(orders: Array<{ id: number; order: number }>) {
    const updates = orders.map(({ id, order }) =>
      this.prisma.homeResources.update({
        where: { id },
        data: { order },
      }),
    );

    return Promise.all(updates);
  }
}

5.2 DTO 定义

typescript
// src/modules/home/dto/create-home-resource.dto.ts
export class CreateHomeResourceDto {
  title: string;
  subtitle?: string;
  url?: string;
  image?: string;
  desc?: string;
  module?: string;
  type?: string;
  icon?: string;
  order?: number;
}

// src/modules/home/dto/update-home-resource.dto.ts
import { PartialType } from '@nestjs/mapped-types';
import { CreateHomeResourceDto } from './create-home-resource.dto';

export class UpdateHomeResourceDto extends PartialType(CreateHomeResourceDto) {}

5.3 使用示例

typescript
// 查询示例
const resources = await this.prisma.homeResources.findMany({
  where: {
    module: 'home',
  },
  orderBy: [
    { order: 'asc' },
    { createdAt: 'desc' },
  ],
  select: {
    id: true,
    title: true,
    image: true,
  },
});

// 创建示例
const resource = await this.prisma.homeResources.create({
  data: {
    title: '新资源',
    subtitle: '副标题',
    url: 'https://example.com',
    module: 'home',
    order: 100,
  },
});

// 更新示例
const updated = await this.prisma.homeResources.update({
  where: { id: 1 },
  data: {
    title: '更新后的标题',
    order: {
      increment: 1,  // order = order + 1
    },
  },
});

// 删除示例
const deleted = await this.prisma.homeResources.delete({
  where: { id: 1 },
});

// upsert 示例
const resource = await this.prisma.homeResources.upsert({
  where: { id: 1 },
  update: { title: '更新标题' },
  create: { title: '新标题' },
});

六、Prisma Client API 速查表

6.1 查询 API 速查

code
Prisma 查询 API 速查:
│
├── findMany()
│   ├── 查询多条记录
│   ├── 返回数组
│   └── 未找到返回 []
│
├── findFirst()
│   ├── 查询第一条记录
│   ├── 返回对象或 null
│   └── 可配合 orderBy 使用
│
├── findUnique()
│   ├── 查询唯一记录(基于 ID 或 unique 字段)
│   ├── 返回对象或 null
│   └── 只能用于 @unique 或 @@unique 字段
│
├── findFirstOrThrow()
│   ├── 查询第一条记录
│   ├── 返回对象
│   └── 未找到抛异常
│
└── findUniqueOrThrow()
    ├── 查询唯一记录
    ├── 返回对象
    └── 未找到抛异常

6.2 CRUD API 速查

code
Prisma CRUD API 速查:
│
├── create(data)
│   └── 创建单条记录,返回对象
│
├── createMany({ data: [] })
│   └── 批量创建,返回 { count: number }
│
├── update({ where, data })
│   └── 更新单条记录,返回对象
│
├── updateMany({ where, data })
│   └── 批量更新,返回 { count: number }
│
├── upsert({ where, update, create })
│   ├── 记录存在:更新
│   ├── 记录不存在:创建
│   └── 返回对象
│
├── delete({ where })
│   └── 删除单条记录,返回对象
│
├── deleteMany({ where })
│   └── 批量删除,返回 { count: number }
│
└── count({ where })
    └── 统计记录数,返回 { count: number }

6.3 查询条件速查

code
Prisma 查询条件操作符:
│
├── 比较操作
│   ├── equals    # 等于
│   ├── not       # 不等于
│   ├── in        # 在列表中
│   ├── notIn     # 不在列表中
│   ├── lt        # 小于
│   ├── lte       # 小于等于
│   ├── gt        # 大于
│   └── gte       # 大于等于
│
├── 字符串操作
│   ├── contains      # 包含
│   ├── startsWith    # 以...开头
│   ├── endsWith      # 以...结尾
│   └── mode          # 模式(default/insensitive)
│
├── 逻辑操作
│   ├── AND   # 且
│   ├── OR    # 或
│   └── NOT   # 非
│
└── 更新操作
    ├── set       # 设置值
    ├── increment # 增加值
    ├── decrement # 减少值
    ├── multiply  # 乘以值
    └── divide    # 除以值

七、常见问题与解决方案

7.1 记录不存在如何处理?

问题:使用 findUnique() 查询记录,返回 null 如何处理?

方案一:使用 findUniqueOrThrow

typescript
try {
  const user = await this.prisma.user.findUniqueOrThrow({
    where: { id: 1 },
  });
  return user;
} catch (error) {
  throw new NotFoundException('用户不存在');
}

方案二:手动判断

typescript
const user = await this.prisma.user.findUnique({
  where: { id: 1 },
});

if (!user) {
  throw new NotFoundException('用户不存在');
}

return user;

7.2 如何实现分页查询?

typescript
async findAll(page: number = 1, limit: number = 10) {
  const skip = (page - 1) * limit;

  const [data, total] = await Promise.all([
    this.prisma.user.findMany({
      skip,
      take: limit,
      orderBy: { createdAt: 'desc' },
    }),
    this.prisma.user.count(),
  ]);

  return {
    data,
    meta: {
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    },
  };
}

7.3 如何优化查询性能?

1. 使用 select 只查询需要的字段

typescript
const users = await this.prisma.user.findMany({
  select: {
    id: true,
    name: true,
    email: true,
  },
});

2. 使用索引

prisma
model User {
  id    Int    @id @default(autoincrement())
  email String @unique  // 自动创建索引
  name  String

  @@index([name])  // 手动创建索引
}

3. 避免查询所有字段

typescript
//  不推荐
const users = await this.prisma.user.findMany();

//  推荐
const users = await this.prisma.user.findMany({
  select: { id: true, name: true },
});

八、学习要点总结

8.1 核心知识点

code
本节核心知识点:
│
├── 业务逻辑层架构
│   ├── Controller → Service → Prisma → Database
│   ├── 参数传递流程
│   └── 各层职责划分
│
├── Controller 参数获取
│   ├── GET → @Query()
│   ├── POST → @Body()
│   ├── PUT → @Body() + @Param()
│   └── DELETE → @Param()
│
├── Prisma Client API
│   ├── 查询:findMany、findFirst、findUnique
│   ├── 创建:create、createMany
│   ├── 更新:update、updateMany、upsert
│   └── 删除:delete、deleteMany
│
└── 最佳实践
    ├── 选择合适的查询方法
    ├── 使用 findUniqueOrThrow 处理不存在
    ├── 使用 select 优化性能
    └── 使用 upsert 简化逻辑

8.2 学习路径规划

code
学习路径:
│
├── 第一阶段:理解概念(1 天)
│   ├── 理解业务逻辑层架构
│   ├── 理解参数传递流程
│   └── 了解 Prisma Client API 分类
│
├── 第二阶段:实践使用(2-3 天)
│   ├── 实现完整的 CRUD 接口
│   ├── 熟练使用查询条件操作符
│   └── 实现分页查询
│
└── 第三阶段:深入应用(持续)
    ├── 关联查询(下一节)
    ├── 事务处理
    └── 性能优化

8.3 重要程度标注

code
重要程度说明:
│
├──  必须掌握
│   ├── 业务逻辑层架构流程
│   ├── Controller 参数获取方式
│   ├── Prisma Client CRUD API
│   └── findUnique、upsert 的使用
│
├──  重要
│   ├── 参数组合使用
│   ├── 查询条件操作符
│   ├── 分页查询实现
│   └── 性能优化技巧
│
└──  了解
    ├── findFirstOrThrow
    ├── findUniqueOrThrow
    └── 批量操作 API

重要提示:这一节是业务逻辑层和 Prisma CRUD 操作的核心内容,理解参数传递流程、熟练使用 Prisma Client API,对实际项目开发非常重要!特别是要掌握 findUnique 和 upsert 的使用,这在实际项目中非常实用!

下一节预告:下一节将学习 Prisma 的关联查询,包括一对一、一对多、多对多关系的处理。