ORM: オブジェクト ↔ テーブル のマッピング クラス / オブジェクト User id: number name: string email: string インスタンス { id: 1, name: "Taro", email: "taro@ex.com" } DBテーブル users id INTEGER PK name VARCHAR email VARCHAR 行(Row) 1 | Taro | taro@ex.com 2 | Hana | hana@ex.com ORM 変換 クラス→テーブル / プロパティ→カラム / インスタンス→行
ORMによるオブジェクトとテーブルのマッピング
ひよこ ひよこ

ORMって「SQLを書かなくてもデータベースを操作できる」って聞いたけど、どういう仕組みなの?

ペンギン先生 ペンギン先生

ORMはObject-Relational Mapping、つまり「オブジェクトリレーショナルデータベースの対応づけ」だよ。プログラムの中で使うクラスやオブジェクトを、データベーステーブルや行に自動的に変換してくれる仕組みなんだ。例えばUserクラスのインスタンスを保存すると、usersテーブルにINSERT文が自動生成されて実行されるイメージだね。

ひよこ ひよこ

なんでわざわざそんな変換が必要なの?直接SQL書けばいいんじゃないの?

ペンギン先生 ペンギン先生

実はプログラミング言語オブジェクトデータベーステーブルって、構造が根本的に違うんだ。これを「インピーダンスミスマッチ」って呼ぶよ。オブジェクトには継承メソッドがあるけどテーブルにはない。オブジェクトは他のオブジェクトへの参照を持つけど、テーブル外部キーで関連づける。この溝を埋めてくれるのがORMなんだ。

ひよこ ひよこ

具体的にはどんな風に対応づけてるの?

ペンギン先生 ペンギン先生

基本ルールは3つ。クラスがテーブルに対応、プロパティ(フィールド)がカラムに対応、インスタンスオブジェクト1個)が行に対応するよ。例えばUserクラスのnameプロパティはusersテーブルのnameカラムになる。関連づけも定義できて、「UserはPostを複数持つ」みたいな1対多の関係をhasMany()やOneToMany()で宣言すると、JOINサブクエリを自動生成してくれるんだ。

ひよこ ひよこ

遅延ローディングとか即時ローディングって何のこと?

ペンギン先生 ペンギン先生

関連データをいつ取りに行くかの戦略だよ。遅延ローディング(Lazy Loading)は「必要になったとき初めてSQLを発行する」方式。例えばuser.postsにアクセスした瞬間にSELECT文が走る。即時ローディング(Eager Loading)は「最初からJOINで一緒に取ってくる」方式だね。遅延ローディングは便利だけど、実は大きな落とし穴があるんだ。

ひよこ ひよこ

落とし穴って何?

ペンギン先生 ペンギン先生

N+1問題だよ。例えば100人のユーザー一覧を表示するとき、まず1回のSQLで100人分を取得する。次に各ユーザーの投稿を表示しようとすると、遅延ローディングでユーザーごとに1回ずつSQLが走って、合計101回のSQLが実行される。これがN+1問題。100人なら101回、1000人なら1001回。対策は即時ローディングで最初から2回のSQLで全部取るか、バッチローディングでまとめて取得することだね。

ひよこ ひよこ

有名なORMってどんなのがあるの?

ペンギン先生 ペンギン先生

JavaならHibernate、PythonならSQLAlchemy、Node.jsならPrismaやTypeORMが有名だよ。特にPrismaは最近人気で、スキーマ定義ファイルからTypeScriptの型を自動生成してくれるから、SQLのタイプミスがコンパイル時に見つかる。各ORMで設計思想が違っていて、大きく分けるとActive RecordパターンとData Mapperパターンの2種類があるんだ。

ひよこ ひよこ

Active RecordとData Mapperってどう違うの?

ペンギン先生 ペンギン先生

Active Recordは、オブジェクト自身がデータベース操作のメソッドを持つパターン。user.save()やUser.find(1)みたいに書ける。Ruby on RailsのActiveRecordやLaravelのEloquentがこれだね。一方Data Mapperは、オブジェクトデータベース操作を分離するパターン。オブジェクトは純粋なデータだけを持ち、別のRepositoryクラスがDB操作を担当する。HibernateやTypeORMがこっちだよ。

ひよこ ひよこ

どっちがいいの?

ペンギン先生 ペンギン先生

小〜中規模ならActive Recordの方がシンプルで書きやすい。でも大規模になるとビジネスロジックとDB操作が混ざって辛くなるんだ。Data Mapperはテストしやすいし、ドメインロジックをDBに依存させずに書ける。ただ設定やコード量が増える。これは「便利さ vs 柔軟性」のトレードオフだね。

ひよこ ひよこ

ORMを使うとパフォーマンスが悪くなることってあるの?

ペンギン先生 ペンギン先生

あるよ。ORMが生成するSQLは汎用的だから、複雑な集計やバルクインサートでは手書きSQLの方が圧倒的に速いことがある。ベテランエンジニアの間では「ORMは8割のクエリを楽にして、2割のクエリを地獄にする」って言われることもあるんだ。だから多くのORMは生SQLを書ける逃げ道を用意しているし、Prismaのようにクエリビルダー寄りのアプローチで「型安全だけどSQLに近い」書き方を提供するものも増えてるよ。使い分けが大事だね。