<CodeLearn/>
データベース レッスン4

ORM(Prisma)

コードからデータベースを安全かつ効率的に操作しよう

ORMとは?

ORM(Object-Relational Mapping)は、 データベースのテーブルをプログラミング言語のオブジェクトとして扱えるようにするツールです。 SQL を直接書かずに、TypeScript/JavaScript のコードでデータベース操作ができます。

SQL を直接書く場合

const result = await db.query(
  'SELECT * FROM users WHERE id = $1',
  [userId]
);

ORM(Prisma)を使う場合

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

Prisma は Node.js / TypeScript で最も人気のある ORM です。 型安全な API、自動マイグレーション、直感的なスキーマ定義が特徴です。

Prisma のセットアップ

Prisma をプロジェクトにインストールして初期化します。

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

# 初期化(prisma/schema.prisma が生成される)
npx prisma init

.env ファイルにデータベースの接続URLを設定します。

# .env
DATABASE_URL="postgresql://user:password@localhost:5432/mydb?schema=public"

# SQLite の場合(手軽に始められる)
# DATABASE_URL="file:./dev.db"

スキーマ定義

prisma/schema.prisma にデータモデルを定義します。 Prisma独自の記法で、テーブル構造とリレーションを宣言的に記述できます。

// prisma/schema.prisma

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

datasource db {
  provider = "postgresql"  // "sqlite" や "mysql" も可
  url      = env("DATABASE_URL")
}

// ユーザーモデル
model User {
  id        Int      @id @default(autoincrement())
  name      String
  email     String   @unique
  age       Int?     // ? はオプショナル(NULL許可)
  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

  // リレーション
  posts   Post[]
  profile Profile?

  @@map("users") // テーブル名を指定
}

// 投稿モデル
model Post {
  id        Int      @id @default(autoincrement())
  title     String
  body      String?
  published Boolean  @default(false)
  createdAt DateTime @default(now()) @map("created_at")

  // リレーション(1対多)
  author   User @relation(fields: [authorId], references: [id])
  authorId Int  @map("author_id")

  tags TagOnPost[]

  @@map("posts")
}

// プロフィールモデル(1対1)
model Profile {
  id     Int     @id @default(autoincrement())
  bio    String?
  avatar String?

  user   User @relation(fields: [userId], references: [id])
  userId Int  @unique @map("user_id")

  @@map("profiles")
}

// タグモデル
model Tag {
  id    Int    @id @default(autoincrement())
  name  String @unique
  posts TagOnPost[]

  @@map("tags")
}

// 中間テーブル(多対多)
model TagOnPost {
  post   Post @relation(fields: [postId], references: [id])
  postId Int  @map("post_id")
  tag    Tag  @relation(fields: [tagId], references: [id])
  tagId  Int  @map("tag_id")

  @@id([postId, tagId])
  @@map("post_tags")
}

マイグレーション

スキーマの変更をデータベースに反映するにはマイグレーションを実行します。 マイグレーションは SQL の変更履歴を管理するファイルです。

# マイグレーションの作成と実行
npx prisma migrate dev --name init

# 上のコマンドで以下が行われる:
# 1. prisma/migrations/ にSQLファイルが生成される
# 2. データベースにテーブルが作成される
# 3. Prisma Client が再生成される

# スキーマを変更した場合も同様
npx prisma migrate dev --name add_avatar_to_profile

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

# Prisma Client の手動再生成
npx prisma generate

# データベースの中身を確認(GUIツール)
npx prisma studio

Prisma Client で CRUD 操作

Prisma Client は型安全な API を提供します。TypeScript の補完が効くため、 カラム名のタイポやデータ型の間違いをコンパイル時に検出できます。

import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

// === CREATE(作成) ===
const newUser = await prisma.user.create({
  data: {
    name: "田中太郎",
    email: "tanaka@example.com",
    age: 28,
  },
});

// リレーション付きで作成
const userWithPost = await prisma.user.create({
  data: {
    name: "鈴木花子",
    email: "suzuki@example.com",
    posts: {
      create: [
        { title: "初投稿", body: "Prismaで作成!", published: true },
        { title: "2つ目の投稿", body: "リレーション便利!" },
      ],
    },
  },
  include: { posts: true }, // リレーション先も返す
});

// === READ(取得) ===
// 全件取得
const allUsers = await prisma.user.findMany();

// 条件付き取得
const adults = await prisma.user.findMany({
  where: { age: { gte: 20 } },
  orderBy: { createdAt: "desc" },
  take: 10, // LIMIT
});

// 1件取得
const user = await prisma.user.findUnique({
  where: { email: "tanaka@example.com" },
  include: { posts: true, profile: true },
});

// === UPDATE(更新) ===
const updated = await prisma.user.update({
  where: { id: 1 },
  data: { name: "田中太郎(更新)", age: 29 },
});

// === DELETE(削除) ===
const deleted = await prisma.user.delete({
  where: { id: 1 },
});

まとめ

  • ORM はデータベースのテーブルをオブジェクトとして扱うツール
  • Prisma は TypeScript と相性が良く、型安全なデータベース操作ができる
  • schema.prisma でデータモデルとリレーションを宣言的に定義する
  • マイグレーションでスキーマの変更をデータベースに安全に反映する
  • Prisma Client の create / findMany / update / delete で CRUD 操作を行う
  • include でリレーション先のデータも一緒に取得できる