社内技術発表会でORMについて話しました
以下、社内ブログに上げた記事
手抜きでゴメンなさい。
以下のcodezineの記事を見てください。
http://codezine.jp/article/detail/5858
記事の方ではPrimaryKeyからのデータ取得の例しか記載されてないのでPrimaryKey以外のSELECTの仕方を記載します。
(私がDoctrineとPropleしか経験が無いのでその2つのみですが)
・Dctrine
$q = Doctrine_Query::create()
->select('a.name')
->from('Account a')
->where('a.amount > 2000');
$accounts = $q->execute();
Prople
$c = new Criteria();
$criterion = $c->getNewCriterion(UserPeer::ID, 1);
$criterion->addOr($c->getNewCriterion(UserPeer::ACCOUNT, 'hoge'));
$c->add($criterion);
$c->add(UserPeer::ID, 10, Criteria::LESS_THAN);
$user = UserPeer::doSelect($c);
DoctrineとPropelを使ってみての感想ですが、Doctrineの方はORMを使いながらもメソッド名がSQLライクなので生成されるSQLがイメージしやすい、Propelの方は生成されるSQLはイメージしにくいがオブジェクト指向は理解しているがSQLは苦手という人には使いやすいと思います。
発表後に出た質問
・設定ファイル(xmlなど)を用意するのは手間じゃないか?
たしかに設定ファイルが無いよりは一手間かかりますが、フレームワークによっては1つの設定ファイルからテーブル作成用のSQLとORMのコードを生成してくれる物もあるので、他のライブラリやフレームワークと一緒に利用することで手間を軽減できる場合もある
・グループなどのリレーショナルなどは出来るのか?
設定ファイルにリレーショナルの情報をきちんと記述してあげればリレーショナル関係もクラスの情報として保持できます。
・パフォーマンス等の理由により使用できない場合が考えられるが、その場合ORMを使ったプロジェクトと使わないプロジェクトが存在してダブルスタンダードとなり両方勉強する必要がないか?
個人的な見解としてORM等のライブラリを使わないで開発できる能力は最低限の必要なものだと思っています。
その上で0からも作れるけどもっと楽したいよねって時にORMなりフレームワークなり使えばいいかなと思います。
以下、技術発表に参加できなかった技術リーダーとのやり取り。
・技術リーダー
http://www.symfony-project.org/doctrine/1_2/ja/06-Working-With-Data
ここみると複雑なWHEREの追加がどうなってるのか気になるかな。
例えば (A or B) and (C or D)を実装すると
$q->where('A=?', 1)
->orWhere('B=?', 1)
->andWhere('C=?', 1)
->orWhere('D=?', 1)
でいいのかな・・・?
A or (B and C) or D
と解釈されそう?
このあたり知ってたら教えて欲しいです。
UNIONもないしある程度VIEWで実装済みであることを前提としてるのかな。
後は「データを削除する」のサンプルなんぞを見ても分かるけど
$user = Doctrine::getTable('User')->find(1);
$user->delete();
$deleted = Doctrine_Query::create()
->delete()
->from('User u')
->where('u.id = ?', 1)
->execute();
の2パターンあって、上はオブジェクト的だが無駄な処理有り、下はSQL的だが無駄な処理無し。
でもORM使うなら上がデフォなんだろうか?それとも下でガリガリ書くの?という疑問が浮かぶ。
・yanchi
・(A or B) and (C or D)の検索
Doctrineは実務では使ってないのでPropelほど詳しくないのですが質問の検索条件を投げるとしたら多分以下のようになります。
$table = Doctrine::getTable('User')->createQuery('User u');
$or1 = Doctrine_Query::create()
->Where(A)
->orWhere(B);
$or2 = Doctrine_Query::create()
->Where(C)
->orWhere(D);
$table->where($or1)->andWhere($or2 );
()でくくった優先度のQueryを個別に作り、それをand(又はor)で繋ぐ感じになります。
以下の方法でもいけるみたいですが
$q = Doctrine::getTable('User')->createQuery('User u')
->where(A or B)
->andWhere(C or D);
・削除処理
削除の処理については上のオブジェクトを取得してから削除が一般的です。
下の場合は複数(数千件とか)のデータを纏めて消すときに使用します。
こんな感じでいいですか?
・技術リーダー
回答ありがとです。
ちょっとさらっと雑談したけど毎回DELETEのたびに必ずSELECTを発生させるのはどうなのか、というのはありますかね。
コストは安くても明らかに無駄な処理なので。
Doctrineはがっつり触ってないので(A or B) and (C or D)の検索 の仕方間違ってたらご指摘ください。
今見なおしたら「UNIONもないしある程度VIEWで実装済みであることを前提としてるのかな」に答えてないなぁ。
まぁ、DoctrineでもPropelでも生SQL投げる方法あるし、そもそも個人的な見解だとそんな複雑なSQL投げないといけないならテーブル定義見直そうよって思うんだけど。。。