ActiveRecordとSequel

RubyのORMはいくつかあるが、Railsで使われているActiveRecordが最もメジャーで、その次くらいにSequelがあると認識している。

最近ふとしたことで両方を使ってみた感想。どちらも、テーブル名を複数形(sつき)にしなきゃいけなかったり、いろいろ面倒だった。勝手に変化させないで欲しいんだよねー。おれ、プログラム上で語尾を変化させるのは好きじゃないのよね。-erと-orの違いとか、sつけるのつけないの、esやiesになるの、受け身だからedだとか、haveかhasかhadとかhavenとか、isかareか、theをつけるかつけないかとか、datumかdataかなんて、考えたくないじゃん。ただのシンボルなんだから。

そういう細かいアレがあるにせよ、どちらも割と使えたんだけど、ActiveRecordはDB側のconstraintを指定できず、例えばカジュアルにuniqueをつけたいと思ってもできない。Ruby側でvalidationを書くかインデックスにuniqueをつけるかしなければならなかったりして、今のところSequelのほうが使用感は良い。ActiveRecordがモデルの記述を重点しているのに対し、Sequelはモデルがなくてもかなりイイトコまで働ける感じ。

例えばJoinの書き方に関してはSequelのほうが直感的で分かりやすい。現代においてSQLを使うというのはすなわちJoinを使うということであるようなのだが、Sequelはモデルに何も書かなくてもキーをjoinの引数に指定するだけでjoinできる。ActiveRecordはモデルにリレーション(belongs_toだの何だの)をつけないとjoinできない。そもそもjoinじゃなくてjoinsなんだよな…三人称単数現在…そこでそうするか。SQLではJOINSなんて書けないよ。んなこと言うならおめーはActiveRecordsじゃねえのかッコラー!!

ただSequelのjoinは同じカラム名のものがあるときに、間違った(と私が思う)結果が返ってきてしまうことに気づいた。意味的に考えてバグっている気がする。

つまり、こうだ。

[pyg language=”ruby”]
#! /usr/bin/ruby

require ‘sequel’
require ‘pp’

DB=Sequel.sqlite

DB.create_table :tbl1s do
primary_key :id
String :value
end

DB.create_table :tbl2s do
primary_key :id
String :value2
Integer :tbl1_id
end

class Tbl1 < Sequel::Model ; end class Tbl2 < Sequel::Model ; end if $0==__FILE__ Tbl1.insert(:value=>“tbl1data1″) # tbl1s.id=>1
Tbl1.insert(:value=>”tbl1data2″) # tbl1s.id=>2
Tbl2.insert(:value2=>”tbl2data1″, :tbl1_id=>2) # tbl2s.id=>1
Tbl2.insert(:value2=>”tbl2data2″, :tbl1_id=>1) # tbl2s.id=>2
# SELECT * FROM tbl1s INNER JOIN tbl2s ON (tbl2s.tbl1_id = tbl1s.id)
t=Tbl1.join(Tbl2, :tbl1_id=>:id).first
pp t # Tbl1{:id=>1, :value=>”tbl1data2″, :value2=>”tbl2data1”, :tbl1_id=>2}
end
[/pyg]

Tbl1.join(Tbl2)だと、Tbl1のオブジェクトが返るが、その:idはなんとTbl2のものなので、戻ってきたTbl1オブジェクトをそのまま扱っていると大変な事故が起きる。例えばこれで中身を見てdeleteしたら、思ったのと異なるものが削除されてしまう(No!)。これを避けるには、こんなふうに↓書かなければならなかった。

Tbl1.join(Tbl2, :tbl1_id=>:id).select(*Tbl1.columns.map{|m| Sequel.qualify(:tbl1s, m) })

これって、モデルで関連をちゃんと書けばいいという話なんだろうか? 戻るのはTbl2じゃなくてTbl1のオブジェクトなんだから、selectやモデル定義で小細工しなくてもTbl1側のカラム名が優先されるのが当然に思えるんだけど。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です