ORMの使う使わないについて
- とあるコミュニティでORMを使う使わない、使い方の議論があった
- 自分の考えを整理するためにも今自分がこうしたほうがいいなって運用方法を書き出してみる
- 個人の好みによるものが大きいので一意見として
- ここではサーバーアプリケーションでの文脈
ORMってそもそも何
前提知識としてORMとは
- インピーダンスミスマッチを解消するもの
- インピーダンスミスマッチとは
- 概念モデルと論理モデルの違いを埋める
- アプリケーションの要件にそった概念モデル(Entity)は、論理モデル(テーブル)と1対1になるとは限らない
- こういったDB側の都合をアプリケーションで意識しないで済むようになるもの
ORMを使うか使わないか
でもDB側の都合を意識しないで済むって言うけど結局パフォーマンスとか考えたら意識しなくちゃいけないよね?
で、ORM使ってWhereとか書き始めたらそれSQL書いているだけだよね?ORMいらなくない?
っていうのが今回のORM使う使わない問題の根幹としてあると思う
サーバーアプリケーションからDBの値を引く
サーバーアプリケーションからプログラムを書いて、DBから値を読み込み、アプリケーションで使用する、その方法は大体こんな感じだと思う
個人的意見
個人の好みによる ORMでクエリビルダーを有効活用するのが自分の最適解
SQLを直接書いてORMを用いずマッピング
ここからは各方法を実際のコード(C#)で良いところ、悪いところを挙げていく
ORMを使用しないマッピングの場合、
var sql = $@" SELECT USER.NAME ARTICLE.TITLE FROM USER INNER JOIN ARTICLE ON ARTICLE.ID = USER.ID WHERE ID = @id "; return Connection.Query(sql, new { id }); // 上の呼び出し元 foreach(result in results) { var name = user["Name"] var title = user["Title"] // 何かの処理 }
良いところ
- クエリを直接かけるのでハイパフォーマンス
- 特別構文解釈の負荷もかかりにくい
悪いところ
- 取り回しが悪い
そのままSQLだからしっかりデータベースのことを考えてチューニングできるのでいい
でもビジネス要件に耐えられるものではないかなあと思ってしまう
上記は単純なSQLだが複雑度が増し、その複雑度の増したSQLが画面やAPIによって若干の条件が変わるごとに同じSQLを書くことになったりして辛くなるのでは
サーバーアプリケーションにおいてはこれを用いることによって行えるパフォーマンス向上も一般的なサーバーアプリケーションでは早すぎる最適化なのではと思う
ORMとSQL書くパターン
var sql = $@" SELECT USER.NAME ARTICLE.TITLE FROM USER INNER JOIN ARTICLE ON ARTICLE.ID = USER.ID WHERE ID = @id "; // Userクラスにマッピングされる return Connection.Query<User>(sql, new { id });
良いところ
悪いところ
- 取り回しが悪い
これも前述の取り回しの問題が解決できない
ORMでクエリビルダーで書くパターン
C#だとメソッドで書くパターンとクエリ式というもので書くパターンがある
// メソッド形式 var result1 = _context.Users .Join( _context.Articles, user => user.ID, article => article.UserId, (user, article) => new { user, article }) .Where(m => m.user.ID == id) .Select(m => new { m.user.Name, m.article.Title }).ToArray(); // クエリ式 var result2 = (from user in _context.Users join article in _context.Articles on user.ID equals article.UserId where user.ID == 1 select new { user.Name, article.Title }).ToArray();
良いところ
- (静的解析であれば)補完が効く
- 共通化、拡張がしやすい
悪いところ
- 独自構文、メソッドを覚えなくてはいけない
- 発行されるSQLを把握しとく必要がある
これのいいところは取得するカラムの絞り込みを後から行いやすかったり、Whereの共通化、追加を行いやすい
JoinやWhereの部分を拡張メソッドとして切り出してあげることも可能
public static IQueryable<User> HasArticle(this IQueryable<User> query) { return query.Where(user => user.Articles.Any()); } var result = _context.Users .HasArtice() .ToArray();
みたいな
ここらへんはORMによりけり
C#のクエリ式はSQLそのままに近く、かつプログラミング言語の機能を生かせるのでかなりいいと思っている
リッチなORMであれば上記のようなクエリビルダーを使うこともないかもしれない
ここらへんは後でもう少し深堀したいところ