ORM
オブジェクト指向のコードとリレーショナル DB のテーブルをマッピングするライブラリ
データベース開発ツール
ORM とは
ORM (Object-Relational Mapping) は、プログラミング言語のオブジェクトとリレーショナル DB のテーブルをマッピングし、SQL を直接書かずにデータベースを操作するライブラリである。
ORM の例
| ORM | 言語 | 特徴 |
|---|---|---|
| Prisma | TypeScript | 型安全、スキーマファースト |
| Drizzle | TypeScript | 軽量、SQL に近い |
| TypeORM | TypeScript | デコレータベース |
| SQLAlchemy | Python | 最も成熟 |
| GORM | Go | シンプル |
Prisma の使い方
// schema.prisma
model User {
id String @id @default(uuid())
name String
email String @unique
orders Order[]
}
model Order {
id String @id @default(uuid())
amount Int
userId String
user User @relation(fields: [userId], references: [id])
}
// 型安全なクエリ
const user = await prisma.user.findUnique({
where: { id: '123' },
include: { orders: true }, // リレーションを含む
});
// user の型: User & { orders: Order[] }
ORM vs 生 SQL vs クエリビルダー
| アプローチ | 抽象度 | 型安全 | 例 |
|---|---|---|---|
| ORM | 高い | ✅ | Prisma, TypeORM |
| クエリビルダー | 中程度 | ✅ | Drizzle, Knex |
| 生 SQL | 低い | ❌ | pg ライブラリ |
ORM の落とし穴
N+1 問題
// ❌ N+1: ユーザーごとに注文を個別取得
const users = await prisma.user.findMany();
for (const user of users) {
const orders = await prisma.order.findMany({ where: { userId: user.id } });
}
// ✅ include で一括取得
const users = await prisma.user.findMany({ include: { orders: true } });
複雑なクエリ
ORM では表現しにくい複雑なクエリ (ウィンドウ関数、CTE) は生 SQL にフォールバックする。
const result = await prisma.$queryRaw`
SELECT user_id, SUM(amount) as total
FROM orders
GROUP BY user_id
HAVING SUM(amount) > 10000
`;
DynamoDB と ORM
DynamoDB は RDB ではないため、従来の ORM は使えない。DynamoDB 用のライブラリ (ElectroDB, DynamoDB Toolbox) がある。
Lambda での選択
| ケース | 推奨 |
|---|---|
| RDS + 複雑なリレーション | Prisma |
| RDS + パフォーマンス重視 | Drizzle or 生 SQL |
| DynamoDB | AWS SDK 直接 or ElectroDB |
現場での応用を知るには関連書籍も役立つ。