【初心者向け】Prisma ORMの使い方を基礎から実践まで徹底解説

kento_morota 16分で読めます

「自社システムのデータベース操作にSQL文を直接書くのは手間だし、ミスも怖い」「もっと安全で効率的にデータベースを扱えるツールはないか」――そんな課題を解決するのがPrisma ORMです。

本記事では、Prisma ORMの使い方を基礎から実践まで、環境構築・データベース設計・CRUD操作の具体的なコード例を交えて初心者にもわかりやすく解説します。

Prisma ORMとは?データベース操作を簡単にする仕組み

「Excelでの顧客管理が限界に来ている」「SaaSツールでは自社の業務フローに合わない」――こうした課題を解決するために自社専用のWebシステムを検討する際、避けて通れないのがデータベース操作です。

Prisma ORM(Object-Relational Mapping)は、データベース操作を直感的かつ安全に行えるツールです。従来のSQL文を直接書く方法と比べて、TypeScriptやJavaScriptのコードでデータベースを扱えるため、開発スピードが大幅に向上します。

この記事では、Prisma ORMの使い方を基礎から実践まで解説します。環境構築からデータベース設計、実際のCRUD操作まで、具体的なコード例を交えながら説明していきます。

ORMの役割とPrismaの特徴

ORMとは「Object-Relational Mapping」の略で、データベースのテーブルをプログラミング言語のオブジェクトとして扱える技術です。ORMの基本概念についてはORMとは?メリット・デメリット解説もご覧ください。

通常、データベース操作にはSQL文が必要ですが、ORMを使うとプログラミング言語の自然な書き方でデータベースを操作できます。

SQL文での記述:

SELECT * FROM customers WHERE id = 1;

Prisma ORMでの記述:

const customer = await prisma.customer.findUnique({
  where: { id: 1 }
});

Prismaが選ばれる主な理由は以下の3点です。

1. 型安全性による開発の安心感

TypeScriptとの相性が抜群で、データベースのスキーマから自動的に型定義を生成します。存在しないカラム名を指定するとエディタ上で即座にエラー表示されるため、実行前にバグを発見できます。

2. 優れた開発者体験

直感的なAPI設計、強力な自動補完、充実したCLIツールにより、開発期間の短縮とコストの削減が実現できます。

3. Schema駆動開発による設計の明確化

一つのSchemaファイルでデータベース全体の構造を管理できるため、チーム開発やドキュメント管理が容易になります。

Prismaが向いているプロジェクト

Prisma ORMは以下のようなプロジェクトに適しています。

適しているケース:
- 中小規模のWebアプリケーション(顧客管理、案件管理、予約システムなど)
- TypeScript/Node.jsを使ったプロジェクト
- スタートアップや新規事業のスピード重視の開発
- 段階的な機能追加が想定されるシステム

向いていないケース:
- 超大規模システムで極限までパフォーマンスを追求する場合
- 既存の複雑なレガシーデータベースとの統合

Prismaの基本構成と必要な環境

3つの主要コンポーネント

Prismaは主に3つのコンポーネントで構成されています。

1. Prisma Client

アプリケーションコードからデータベースを操作するライブラリです。データの作成、取得、更新、削除(CRUD操作)をTypeScriptやJavaScriptで記述できます。

2. Prisma Migrate

データベースのスキーマ変更を管理するツールです。変更履歴が残るため、チーム開発での同期や本番環境への適用が安全に行えます。

3. Prisma Studio

ブラウザ上で動作するデータベース管理ツールです。npx prisma studioコマンドで起動し、テーブルのデータを表形式で確認・編集できます。

Prisma Schemaファイルの構造

Prisma Schemaprisma/schema.prismaという名前で保存され、以下の3つの情報を記述します。

// データソース設定
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

// ジェネレーター設定
generator client {
  provider = "prisma-client-js"
}

// データモデル定義
model Customer {
  id        Int      @id @default(autoincrement())
  name      String
  email     String   @unique
  createdAt DateTime @default(now())
  orders    Order[]
}

対応データベースと必要な環境

対応データベース:
- PostgreSQL: 高機能で本番環境に最適
- MySQL: 普及率が高くレンタルサーバーでも利用可能
- SQLite: 軽量で開発環境やプロトタイプに最適

必要な環境:
- Node.js(バージョン14.17以上)
- npm または yarn
- Visual Studio Code(推奨)
- TypeScript(推奨)

環境構築と初期設定の手順

プロジェクトの作成とPrismaのインストール

# プロジェクトディレクトリの作成
mkdir my-prisma-project
cd my-prisma-project
npm init -y

# TypeScriptのインストール
npm install typescript ts-node @types/node --save-dev
npx tsc --init

# Prismaのインストール
npm install prisma --save-dev
npm install @prisma/client

Prisma Schemaの作成

# Prismaの初期化(SQLiteを使用)
npx prisma init --datasource-provider sqlite

このコマンドで以下のファイルが生成されます:
- prisma/schema.prisma:スキーマファイル
- .env:環境変数ファイル

データベース接続の設定

.envファイルでデータベース接続情報を設定します。

# SQLiteの場合
DATABASE_URL="file:./dev.db"

# PostgreSQLの場合
DATABASE_URL="postgresql://user:password@localhost:5432/mydb?schema=public"

重要: .envファイルは機密情報を含むため、.gitignoreに追加してGitにコミットしないようにしましょう。

Prisma Clientの生成

npx prisma generate

生成されたクライアントを使用する基本的なコード:

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

async function main() {
  console.log('Prisma Clientが正常に動作しています')
}

main()
  .catch((e) => {
    console.error(e)
    process.exit(1)
  })
  .finally(async () => {
    await prisma.$disconnect()
  })

データベース設計:Schemaでテーブルを定義する

モデル定義の基本

model Customer {
  id        Int      @id @default(autoincrement())
  name      String
  email     String   @unique
  phone     String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

各要素の説明:
- @id:主キー
- @default(autoincrement()):自動採番
- String?:NULL許可
- @unique:一意制約
- @updatedAt:更新時に自動更新

フィールドの型とオプション

主なデータ型:
- String:文字列
- Int:整数
- Float:浮動小数点数
- Boolean:真偽値
- DateTime:日時
- Json:JSON形式

実用的な例:

model Project {
  id          Int       @id @default(autoincrement())
  projectCode String    @unique
  name        String
  status      String    @default("draft")
  startDate   DateTime?
  budget      Int?
  description String?   @db.Text
  createdAt   DateTime  @default(now())
  updatedAt   DateTime  @updatedAt
}

リレーションの定義

1対多のリレーション:

model Customer {
  id     Int     @id @default(autoincrement())
  name   String
  orders Order[]
}

model Order {
  id         Int      @id @default(autoincrement())
  amount     Int
  customerId Int
  customer   Customer @relation(fields: [customerId], references: [id])
}

多対多のリレーション:

model Project {
  id      Int             @id @default(autoincrement())
  name    String
  members ProjectMember[]
}

model Member {
  id       Int             @id @default(autoincrement())
  name     String
  projects ProjectMember[]
}

model ProjectMember {
  id        Int      @id @default(autoincrement())
  projectId Int
  memberId  Int
  role      String   @default("member")
  project   Project  @relation(fields: [projectId], references: [id])
  member    Member   @relation(fields: [memberId], references: [id])

  @@unique([projectId, memberId])
}

マイグレーションの実行

スキーマを定義したら、マイグレーションでデータベースに反映します。

# 開発環境でのマイグレーション
npx prisma migrate dev --name init

# 本番環境でのマイグレーション
npx prisma migrate deploy

Prisma Clientを使ったCRUD操作

データの作成(Create)

// 単一データの作成
const customer = await prisma.customer.create({
  data: {
    name: '山田太郎',
    email: 'yamada@example.com',
    phone: '090-1234-5678'
  }
})

// 関連データも同時に作成
const customerWithOrder = await prisma.customer.create({
  data: {
    name: '佐藤花子',
    email: 'sato@example.com',
    orders: {
      create: [
        { amount: 10000 },
        { amount: 5000 }
      ]
    }
  }
})

データの取得(Read)

// 単一データの取得
const customer = await prisma.customer.findUnique({
  where: { id: 1 }
})

// 複数データの取得
const customers = await prisma.customer.findMany({
  where: {
    email: { contains: '@example.com' }
  },
  orderBy: { createdAt: 'desc' },
  take: 10
})

// 関連データを含めて取得
const customerWithOrders = await prisma.customer.findUnique({
  where: { id: 1 },
  include: { orders: true }
})

データの更新(Update)

// 単一データの更新
const updated = await prisma.customer.update({
  where: { id: 1 },
  data: { phone: '090-9876-5432' }
})

// 複数データの更新
const updateMany = await prisma.customer.updateMany({
  where: { email: { contains: '@example.com' } },
  data: { status: 'verified' }
})

データの削除(Delete)

// 単一データの削除
const deleted = await prisma.customer.delete({
  where: { id: 1 }
})

// 複数データの削除
const deleteMany = await prisma.customer.deleteMany({
  where: { createdAt: { lt: new Date('2023-01-01') } }
})

実務で役立つ便利な機能

複雑な検索条件

const results = await prisma.customer.findMany({
  where: {
    AND: [
      { email: { contains: '@example.com' } },
      { createdAt: { gte: new Date('2024-01-01') } }
    ],
    OR: [
      { name: { contains: '山田' } },
      { name: { contains: '佐藤' } }
    ]
  },
  orderBy: [
    { createdAt: 'desc' },
    { name: 'asc' }
  ]
})

トランザクション処理

await prisma.$transaction(async (prisma) => {
  const order = await prisma.order.create({
    data: { customerId: 1, amount: 10000 }
  })

  await prisma.customer.update({
    where: { id: 1 },
    data: { totalSpent: { increment: 10000 } }
  })
})

よく使うCLIコマンド

# スキーマの検証
npx prisma validate

# Prisma Studioの起動
npx prisma studio

# データベースの初期化
npx prisma db push

# マイグレーションの状態確認
npx prisma migrate status

トラブルシューティングと注意点

初心者がつまずきやすいポイント

問題 原因 対処法
Cannot find module '@prisma/client' Prisma Clientが未生成 npx prisma generateを実行
スキーマの変更が反映されない 生成コマンドを実行していない 変更後に必ずgenerateを実行
マイグレーションエラー データベースとスキーマの不整合 npx prisma migrate resetで初期化

チーム開発での注意点

  • マイグレーションファイルは必ずGitにコミットする
  • .envファイルは.gitignoreに追加する
  • スキーマ変更時はチームメンバーに共有し、prisma migrate devを実行してもらう

まとめ

Prisma ORMを使うことで、データベース操作が直感的かつ安全になり、開発スピードが大幅に向上します。型安全性により属人化を防ぎ、誰でも安心してシステムを扱える環境が整います。

中小企業が「Excelや既製品のSaaSでは限界がある」という段階で、自社にちょうどいい業務システムを構築する際には、Prisma ORMは非常に有力な選択肢となります。

次のステップとして:
- 実際のプロジェクトでCRUD操作を実装してみる
- リレーションを使った複雑なデータ構造を設計する
- Next.jsなどのフレームワークと組み合わせてWebアプリケーションを構築する(tRPCとの連携も効果的です)

Harmonic Societyでは、Prisma ORMを活用した業務システム開発をサポートしています。自社に最適な「ちょうどいい」システムづくりをお手伝いしますので、お気軽にご相談ください。

#Prisma#ORM#使い方
共有:

ちょっとした業務の悩みも、気軽にご相談ください。

まずは話だけ聞いてもらう