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に近い」書き方を提供するものも増えてるよ。使い分けが大事だね。