← Назад к вопросам

Как реализовать CRUD-методы в Prisma?

1.8 Middle🔥 161 комментариев
#Soft Skills и рабочие процессы

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как реализовать CRUD методы в Prisma

Что такое Prisma

Prisma — это современный ORM (Object-Relational Mapping) для Node.js и TypeScript. Он упрощает работу с базами данных, предоставляя типизированный API для выполнения операций CRUD (Create, Read, Update, Delete). Prisma работает с PostgreSQL, MySQL, SQLite и другими БД.

Установка и конфигурация

# Установка Prisma
npm install @prisma/client
npm install -D prisma

# Инициализация проекта
npx prisma init

Файл .env:

DATABASE_URL="postgresql://user:password@localhost:5432/mydb"

Определение модели (Schema)

prisma/schema.prisma:

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id        Int     @id @default(autoincrement())
  email     String  @unique
  name      String?
  password  String
  posts     Post[]  @relation("UserPosts")
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  authorId  Int
  author    User    @relation("UserPosts", fields: [authorId], references: [id])
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

Применение миграции:

# Создаёт миграцию
npx prisma migrate dev --name init

# Или для продакшена
npx prisma migrate deploy

CREATE — Создание записей

// lib/prisma.ts
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export default prisma;

// services/userService.ts
import prisma from '@/lib/prisma';

// Способ 1: Простое создание
export async function createUser(email: string, name: string, password: string) {
  const user = await prisma.user.create({
    data: {
      email,
      name,
      password,
    },
  });
  return user;
}

// Способ 2: С возвращением выбранных полей
export async function createUserSafe(email: string, name: string, password: string) {
  const user = await prisma.user.create({
    data: {
      email,
      name,
      password,
    },
    select: {
      id: true,
      email: true,
      name: true,
      createdAt: true,
      // password НЕ возвращаем из соображений безопасности
    },
  });
  return user;
}

// Способ 3: Создание с вложенными данными
export async function createUserWithPost(
  email: string,
  postTitle: string,
  postContent: string
) {
  const user = await prisma.user.create({
    data: {
      email,
      name: 'New User',
      password: 'hashed_password',
      posts: {
        create: {
          title: postTitle,
          content: postContent,
          published: false,
        },
      },
    },
    include: {
      posts: true, // Включает посты в результат
    },
  });
  return user;
}

// Способ 4: Массовое создание
export async function createManyUsers(users: Array<{ email: string; name: string; password: string }>) {
  const result = await prisma.user.createMany({
    data: users,
    skipDuplicates: true, // Пропускает дубликаты
  });
  return result;
}

READ — Чтение записей

// Получение одной записи по ID
export async function getUserById(id: number) {
  const user = await prisma.user.findUnique({
    where: { id },
  });
  return user;
}

// Получение по другому полю
export async function getUserByEmail(email: string) {
  const user = await prisma.user.findUnique({
    where: { email },
  });
  return user;
}

// Получение всех пользователей
export async function getAllUsers() {
  const users = await prisma.user.findMany();
  return users;
}

// С фильтрацией
export async function getUsersByPartialName(namePart: string) {
  const users = await prisma.user.findMany({
    where: {
      name: {
        contains: namePart,
        mode: 'insensitive', // case-insensitive поиск
      },
    },
  });
  return users;
}

// С сортировкой и пагинацией
export async function getUsersPaginated(page: number, pageSize: number) {
  const skip = (page - 1) * pageSize;
  
  const users = await prisma.user.findMany({
    skip,
    take: pageSize,
    orderBy: { createdAt: 'desc' },
  });
  
  const total = await prisma.user.count();
  
  return {
    users,
    total,
    pages: Math.ceil(total / pageSize),
  };
}

// С включением связанных данных
export async function getUserWithPosts(id: number) {
  const user = await prisma.user.findUnique({
    where: { id },
    include: {
      posts: {
        orderBy: { createdAt: 'desc' },
        take: 10, // Последние 10 постов
      },
    },
  });
  return user;
}

// Выбор определённых полей
export async function getUserPreview(id: number) {
  const user = await prisma.user.findUnique({
    where: { id },
    select: {
      id: true,
      name: true,
      email: true,
      createdAt: true,
      posts: {
        select: {
          id: true,
          title: true,
        },
        take: 5,
      },
    },
  });
  return user;
}

UPDATE — Обновление записей

// Обновление по ID
export async function updateUser(
  id: number,
  data: { name?: string; email?: string }
) {
  const user = await prisma.user.update({
    where: { id },
    data,
  });
  return user;
}

// Условное обновление
export async function updateUserEmail(id: number, newEmail: string) {
  const user = await prisma.user.update({
    where: { id },
    data: {
      email: newEmail,
      updatedAt: new Date(), // Автоматически обновляется
    },
  });
  return user;
}

// Массовое обновление
export async function publishAllPostsByUser(userId: number) {
  const result = await prisma.post.updateMany({
    where: { authorId: userId },
    data: { published: true },
  });
  return result;
}

// Update или Create (Upsert)
export async function upsertUser(email: string, name: string) {
  const user = await prisma.user.upsert({
    where: { email },
    update: { name },
    create: {
      email,
      name,
      password: 'default_password',
    },
  });
  return user;
}

DELETE — Удаление записей

// Удаление по ID
export async function deleteUser(id: number) {
  const user = await prisma.user.delete({
    where: { id },
  });
  return user;
}

// Массовое удаление
export async function deleteOldUsers(beforeDate: Date) {
  const result = await prisma.user.deleteMany({
    where: {
      createdAt: {
        lt: beforeDate, // lt = less than
      },
    },
  });
  return result;
}

// Удаление с каскадом
// (конфигурируется в schema.prisma)
// model Post {
//   author User @relation(..., onDelete: Cascade)
// }
// При удалении пользователя удалятся все его посты

Практический пример: API endpoint

// pages/api/users/[id].ts
import type { NextApiRequest, NextApiResponse } from 'next';
import prisma from '@/lib/prisma';

type ResponseData = {
  data?: any;
  error?: string;
};

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<ResponseData>
) {
  const { id } = req.query;
  const userId = Number(id);

  try {
    // GET - Чтение
    if (req.method === 'GET') {
      const user = await prisma.user.findUnique({
        where: { id: userId },
        include: { posts: true },
      });
      
      if (!user) {
        return res.status(404).json({ error: 'User not found' });
      }
      
      return res.status(200).json({ data: user });
    }

    // PUT - Обновление
    if (req.method === 'PUT') {
      const { name, email } = req.body;
      
      const user = await prisma.user.update({
        where: { id: userId },
        data: { name, email },
      });
      
      return res.status(200).json({ data: user });
    }

    // DELETE - Удаление
    if (req.method === 'DELETE') {
      const user = await prisma.user.delete({
        where: { id: userId },
      });
      
      return res.status(200).json({ data: user });
    }

    res.status(405).json({ error: 'Method not allowed' });
  } catch (error) {
    console.error('Database error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
}

Обработка ошибок

import { Prisma } from '@prisma/client';

try {
  const user = await prisma.user.create({
    data: { email: 'test@example.com', password: 'pwd' },
  });
} catch (error) {
  if (error instanceof Prisma.PrismaClientKnownRequestError) {
    // P2002 - Unique constraint failed
    if (error.code === 'P2002') {
      console.log('Email already exists');
    }
    // P2025 - Record not found
    if (error.code === 'P2025') {
      console.log('User not found');
    }
  }
}

Итоговый принцип

Prisma упрощает CRUD операции через типизированный API. Используй findUnique для поиска по уникальным полям, findMany для списков, create/update/delete для изменения данных. Всегда обрабатывай ошибки и выбирай нужные поля через select или include для оптимизации запросов.