ORMとは?アプリがデータベースと話す仕組みをわかりやすく解説
ORM(オブジェクト関係マッパー)は、アプリとリレーショナルデータベースの間に入るコードのライブラリです。開発者はデータベースへのクエリをSQLで書く代わりに、プログラミング言語の普通のオブジェクトとしてデータを扱います。たとえば db.booking.create(...) や Booking.find(...) のように書くと、ORMがそれをSQLに変換して実行し、結果をオブジェクトに戻してくれます。代表的なものとして、TypeScriptならPrismaやDrizzle、PythonならSQLAlchemy、C#ならEntity Framework Coreがあります。
AIでアプリを作るときにORMが重要な理由
AIアプリビルダーがデータベースをアプリに追加するときは、通常そこに接続するためのORMも一緒に追加されます。ORMのコードを自分で書く必要はありませんが、存在を知っておくと役に立ちます。
- データモデルはコードの中にあります。 ORMのスキーマファイルは、アプリのデータが何であるかを最も分かりやすく示しています。どのテーブルがあり、各テーブルにどんな項目があり、それらがどうつながっているかが分かります。このファイルを読めば、AIがアプリを正しく理解しているかをすぐに確認できます。
- データベースの変更はマイグレーションを通します。 「顧客に電話番号を追加して」と頼むと、AIはモデルを更新してマイグレーションを作成します。これを知っておくと、変更が本番に反映されるまでに適用が必要になる理由も理解しやすくなります。
- 初期設定で安全です。 ORMは、クエリを安全な形で組み立てるので、SQLインジェクションを防げます。SQLを手で組み立てるアプリでは、これが最もよくあるセキュリティ上の穴の一つです。
- 速度の落とし穴があります。 ORMを使うと、本来1回で済むものを小さなクエリで何百回も実行してしまうことがあります。AIで作られたアプリのページが遅くなる典型的な原因です。
身近なたとえ
英語しか話せない旅行者と、日本語しか話せない店主が、通訳を介して話している場面を想像してください。
旅行者(あなたのアプリ)が「一番安いお茶を3つください」と言うと、通訳(ORM)がそれを正確な日本語(SQL)に訳して店主(データベース)に伝え、答えを英語に訳し直して戻します。
旅行者が日本語を覚える必要は通常ありません。ただし、込み入った交渉では直接話した方が確実です。だからこそ、多くのORMでは必要なときに開発者が生のSQLを書けるようになっています。
ORMの仕組み
Postgresのようなデータベースは、データを行と列を持つテーブルに保存し、SQLで問い合わせます。一方、プログラミング言語はオブジェクトを扱います。たとえば、「日付」「顧客」「状態」を持つ予約です。ORMはこの2つを対応づけます。
| データベース側 | ORM・コード側 |
|---|---|
テーブル bookings | モデル Booking |
| 行 | 1件の予約オブジェクト |
列 starts_at | 項目 startsAt |
外部キー customer_id | リレーション booking.customer |
SELECT、INSERT、UPDATE、DELETE | find、create、update、delete のメソッド |
この4つの操作は、ほぼすべてのアプリの土台になっているCRUDの操作です。
具体例:PrismaでつくるPrismaの予約
ここでは、サロンの予約アプリ向けに簡略化したPrismaのスキーマを例にします。2つのテーブルと、そのつながりを表しています。
model Customer {
id Int @id @default(autoincrement())
name String
email String @unique
bookings Booking[]
}
model Booking {
id Int @id @default(autoincrement())
startsAt DateTime
service String
customer Customer @relation(fields: [customerId], references: [id])
customerId Int
}
わかりやすく言うと、顧客は名前、重複のないメールアドレス、複数の予約を持ちます。各予約は開始時刻とサービス内容を持ち、1人の顧客に属します。
ここで、アプリが「Lenaさんの今後の予約を、近い順に表示したい」と思ったとします。
const bookings = await db.booking.findMany({
where: {
customer: { email: "lena@example.com" },
startsAt: { gte: new Date() },
},
orderBy: { startsAt: "asc" },
});
ORMはこれを次のようなSQLに変換して実行し、予約オブジェクトのリストを返します。
SELECT b.* FROM "Booking" b
JOIN "Customer" c ON c.id = b."customerId"
WHERE c.email = $1 AND b."startsAt" >= $2
ORDER BY b."startsAt" ASC;
$1 と $2 はプレースホルダーです。メールアドレスと日付はクエリの文章とは別に送られるため、SQLインジェクションを防げます。
マイグレーション
その後「顧客が電話番号を登録できるようにして」と頼むと、AIは Customer モデルに phone String? を追加し(? は任意項目を意味します)、マイグレーションを生成します。これは ALTER TABLE "Customer" ADD COLUMN "phone" TEXT; のような小さなSQLスクリプトです。マイグレーションは順番に保存されるので、どのデータベースも同じ構造に合わせられ、変更の履歴も残ります。
言語別の代表的なORM
| 言語 | 代表的なORM |
|---|---|
| TypeScript / JavaScript | Prisma、Drizzle、TypeORM、Sequelize |
| Python | SQLAlchemy、Django ORM、SQLModel |
| C# | Entity Framework Core |
| Java | Hibernate(多くはSpring Data JPA経由) |
| Ruby | Active Record |
ORMによって、SQLをどれだけ隠すかは異なります。Prismaは独自のスキーマ言語とクエリの書き方を使います。Drizzleは型安全性を保ちつつ、SQLの形に近いまま書けるように作られています。一方、クエリビルダーと呼ばれる軽量なツール(TypeScriptのKnexやKyselyなど)は、行を完全なオブジェクトに対応づけることなく、コードの中でSQLを組み立てる手助けをします。
主な用語
| 用語 | 意味 |
|---|---|
| モデル | テーブルと項目をコードで定義したもの。 |
| スキーマ | すべてのテーブル、項目、関係性の全体像。 |
| リレーション | モデル同士のつながり。たとえば、予約が顧客に属していること。 |
| マイグレーション | データベースの構造を変えるための、バージョン管理されたスクリプト。 |
| クエリビルダー | 完全なオブジェクト対応づけをせず、コードでSQLを組み立てる軽量なツール。 |
| N+1問題 | 一覧を取得するクエリを1回実行した後、各項目ごとにさらに1回ずつクエリを実行してしまう問題。規模が大きくなると遅くなります。 |
| 生のSQL | ORMでは扱いにくいときに、手で書くSQL。 |
よくある誤解
- 「ORMはデータベースだ」。 違います。ORMは変換を行う仕組みです。PostgresなどのデータベースはORMとは別に必要です。
- 「ORMを使えば、データを理解しなくてよい」。 設計の悪いテーブルは、ORMを通しても同じように扱いにくくなります。道具よりも、良いデータモデルの方がずっと重要です。
- 「ORMは必ず遅い」。 日常的なクエリであれば問題ありません。遅くなる原因の多くは、N+1問題やインデックスの不足といったパターンで、どちらも改善できます。
- 「ORMを使えばSQLインジェクションの心配は一切ない」。 標準的なORMのメソッドは安全ですが、ユーザーの入力をそのまま埋め込んだ生のSQLは依然として危険です。
- 「スキーマファイルを編集すると、本番のデータベースが変わる」。 マイグレーションを作成し、そのデータベースに適用して初めて変わります。
AIビルダーに頼むときのポイント
- 「データベースのスキーマを見せて、各テーブルと関係性をわかりやすい日本語で説明して。」
- 「このプロジェクトはどのORMを使っていて、マイグレーションはどこにあるの?」
- 「テーブルを変更する前に、既存データに影響があるかを教えて。データがある列は、確認なしに削除しないで。」
- 「遅いページをN+1クエリがないか確認して、リストの絞り込みや並べ替えに使う列にインデックスを追加して。」
- 「ユーザーの入力を使うクエリはすべてORM経由かパラメーターを使うようにして。SQLを文字列で組み立てないで。」
MythexでのORM
アプリでデータを保存する必要があるときは、Mythexがプロジェクト専用のPostgresデータベースを追加します。チャットで頼むか、/database コマンドを使ってください。そして、接続情報をワークスペースと公開済みアプリに自動で設定します(データベース)。その後、エージェントがデータを読み書きするコードを書きます。「Prismaを使って」「SQLAlchemyを使って」「ORMなしでSQLだけ」など、希望があればチャットで伝えてください。スキーマを確認したいときは、いつでも説明を頼めます。ファイルはコードエディターで確認できます。より大きな全体像については、データベースとはとSQLとNoSQLの違いをご覧ください。
よくある質問
ORMとは簡単に言うと何ですか?
ORM(オブジェクト関係マッパー)は、アプリとリレーショナルデータベースの間に入るコードのライブラリです。開発者はプログラミング言語の普通のオブジェクトとしてデータを読み書きでき、裏側でSQLのクエリを自動的に作ってくれます。
ORMにはどんな例がありますか?
代表的なORMには、TypeScriptやJavaScriptならPrismaやDrizzle、PythonならSQLAlchemyやDjango ORM、C#ならEntity Framework Core、JavaならHibernate、RubyならActive Recordがあります。
ORMを使うのとSQLを直接書くのでは、どちらが良いですか?
用途によります。ORMは日常的な読み書きを速く書けて、安全で変更もしやすくします。一方、複雑なレポートや性能が重要なクエリでは、手書きのSQLの方が細かく制御できます。多くのORMは必要なときに生のSQLを使える仕組みを持っています。
マイグレーションとは何ですか?
マイグレーションは、テーブルや列の追加のように、データベースの構造を変更する小さなスクリプトで、バージョン管理されています。ORMはデータモデルからマイグレーションを生成できるので、ノートパソコン、テスト環境、本番環境のすべてのデータベースを同じ構造にそろえられます。