2007-04-07 Sat
Xangoは何かが変らしい
弾さんと話したときに、Xangoが何か変と言っていた。
私が今まで使っていたのは、古いXangoだったので、
今回のHackathonで最新版を見てみようと思う。
変じゃありませんように。
でも、まー、たぶんXangoはやんちゃなので、
POEがついてこないんじゃないかな??
という話をid:nagayamaとした。

ちなみに、弾さんの家に来てみたら昨日帰ったはずの
id:nagayamaとid:yappoがいてビックリ。
夜中に楽しいことがあったらしい。いいなー。
2007-04-06 Fri
libusbとDevice::USBのインストール
YAPC::ASIA 2007で大盛り上がりした、Yappoさんの
Device::USB::MissileLunchersをインストールしようとした。
必要なものは、libusbとlibusbを叩くDevice::USB、
あとは、Device::USB::MissileLunchers(CPANにない)。
libusb
% wget http://prdownloads.sourceforge.net/libusb/libusb-0.1.12.tar.gz % ./confiure % ./make % ./make install
Device::USB
cpanシェルで、install Device::USBするだけ。
・・と、ここまで来たところで、竹迫さんがミサイルを発射したので、
情熱がどこかへ行ってしまった。なので作業終了。
とりあえず、libusbを使うとUSBデバイスの認識や操作を
できるということが頭に刻み付けられたのでおk。
2007-04-06 Fri
CPANモジュールのアップは1回目はノリで
川崎さんにCPANモジュールのアップについて聞いてみたら、
「1回目はノリでアップしちゃえば?」と言われた。
本当にノリでアップして失敗しないようにだけ、気をつけよう。
なんでCPANモジュールのアップを考えるかというと、
自分が研究で使うモジュールを、頻繁にコピーしてるうえに、
そのモジュールを配布することが多くなったから。
自前のモジュールもたまにアップデートするし、
何よりコピーして渡すのは面倒。
「Install hogehoge」すれば、インストールできるよって
言ってあげることで、面倒な作業から開放される人を
何人か見捨ててきたので、そろそろ助けられる人になりたい。
そのためには、まずはアップロードだよね。
実際には、自前のモジュールの置換可能な部分は
極力、既存のモジュールを使うようにしたり、
メソッド名を整備したりとか、いろいろやることは多い。
何事も順番にやろう。
2007-04-06 Fri
Hackathon 1日目
Hackathonに参加させてもらえることになったので、
格好良いことで有名な弾さんのお宅にお邪魔した。
エレベーターに乗る前から驚きの連続だったし、
ドアが開く音にも、中に入ってからも驚いた。
私の想像力を超えた広さだったので、
行く人が口々にすごいと言うのは良く分かった。
家に入ると、すでに石垣さんや川崎さんがいた。
あとKaoとIngyとJessyとLiuと、・・・って、
普段Perlを介してお世話になっている人が
沢山いてミーハーな私はそれだけで感動した。
慣れない雰囲気に慣れるまでに1時間くらいかかった。
Kaoの料理とNaomiさんのもてなしで、みんな幸せだった。
なんというか出てくる食べ物と飲み物が全部おいしい。
甘くないサトイモ入りのお汁粉は、
今年に入って一番衝撃的なデザートだった。
どれもこれも美味しかった。All Dishes were realy tasty!!
いろいろやりながら気合を注入するような日だった。
2007-04-05 Thu
後片付け
クロージングのあと、会場のゴミ拾いをした。
ゴミ拾いを手伝ってくれたハッカーはちょっとだけいた。
とりあえずid:hibomaは手伝ってくれた。ありがとうございます。
ゴミ拾いのあとは梱包とかチケットの半券をカウントするとか。
さらに机を片付けたりなんだりして終了。
最後の机片付けはスピーカーが残って片付けてくれた。
本当に助かりました。ありがとうございます。
みんなで一丸となって片付けたから、
呆気ないほど早く片づけが終わった。そして解散。
今年のYAPCはプレゼンをほとんど見ていないから、
プレゼンの内容はじつはほとんど知らないセッションが大半。
来週の動画公開が楽しみだなー。
2007-04-05 Thu
クロージング
ライトニングトークが終わったあとは、ぼちぼちクロージング。
片付けられるものから順に片付けたよ。
そんで、竹迫さんが作ったエンディングムービーを鑑賞。
2日間のできごとを思い出して、2日の濃さを実感した。
まだ1回もYAPCに来たことがないPerlユーザはYAPCに来たほうがいい。
ハッカーの日常の挙動は、観察するといろいろ発見があるし。
プレゼンではウケを狙いつつ哲学をぶつける人が多いから、
見終わったあと少なからず影響をうけると思う。
YAPCで受けた影響は、日々の開発を実りあるものにしてくれると思う。
少なくとも私はShibuya.pmに行ったらコードが変わったよ。
ムービーが流れた後、自然と拍手が起きた。
去年ほどではないけれど、止まない拍手は心地よかった。
拍手を聞いたら、体の疲れは吹き飛んだ。報われた。
また来年もYAPCがあるといいな。やっぱり東京でいいよ。
ま、どこでやるにしても来年もお手伝いしたいと思いました。
2007-04-05 Thu
ライトニングトーク
ライトニングトークでは、伝説のにぽだんか光臨した。
モニターで見たけど超笑ったよ。
途中から会場で直接みていたけれど、
全体としては、にぽたんとYappoが持っていった感の
強いLTだった。2人のあとの発表者は大変だなーと思った。
2007-04-05 Thu
2007-04-05 Thu
2007-04-05 Thu
ネットワーク問題は一応解決
今日は、一応ネットワーク問題は解決したみたい。
会場内に1つしかなかったSSIDを大きく4つに分けたみたい。
来年もYAPCがあるとしたら会場の無線LANの確保は大切だなー。
2007-04-05 Thu
ノベルティの配布
Yahoo!のトラベルタグを配布することになったので、
3会の会場前の机でトラベルタグを配布した。
なかなか人気で、すぐに100個くらい無くなった。
帰りまでに全部もらわれると嬉しいなー。
他にも、配布してしまって問題ないノベルティは
机の上において自由にお持ちいただくことにした。
2007-04-05 Thu
YAPC-ASIA 2007 2日目
YAPC-ASIA 2007の2日目です。
昨日にひきつづき、ボランティアで参加させていただきました。
今日は朝から大失敗をしてしまいましたが
1日目のうちに大きな仕事は終わってしまった感じで、
全体的に1日目よりゆるく時間が経過した気がしました。
2日目はセッションが2箇所に分かれていて、
1階で行なわれていた英語のセッションは全く聞けませんでした。
日本語のセッションとライトニングトークは聞けました。
2日目は全体的にJiftyを使いたくなるようなことが多かったです。
あとは、強烈なライトニングトークが印象的でした。
細かい感想や出来事は、順次追加エントリを追加します。
最後の最後はスタッフとスピーカーが、みんなで机を片付けて、
細かいものを片付けて終了でした。
オーガナイザーの皆さん、ボランティアのみなさん、
スピーカーのみなさん、お客さま、おつかれさまでした。
来年もYAPC::ASIA 2008があると良いですね。
2007-04-04 Wed
YAPC-ASIA 2007 1日目
今年のYAPCは、ボランティアで参加させていただきました。
こういうカンファレンスは立ち位置が運営側に近い方が、
自分の内面に対し有益な情報量が高いと思います。
YAPCはセッションを全部動画にしているから、
スタッフが仕事に集中できるのもポイントかも。
ほとんどの発表をテレビ画面を通してみることになったから、
細かいことは分かりませんでした。
来週アップされる動画をみようと思います。
細かい感想や出来事は、順次エントリを追加します。
2007-03-28 Wed
CPANを使い始めにくいって聞いた
このまえのブログ合宿で
「CPANのモジュールをインストールとか訳がわかんない」
と聞いて、あー、確かに昔は訳が分からなかったなーと思った。
今も分かってない部分は多いですけど。
Perlを始めたころに困ったのは、サンプル集に「use XML::Simple」と
気軽に書いてあるのでuseしてみたら、XML::Simpleなんて見つからないよ
とエラーメッセージが出てしまったことかな。
研究室のPCだとモジュールが入っていたけど、
自分の環境にはモジュールが入っていなかったみたい。
そもそも、そのころはCPANモジュールが足りないことも分からなくて
本当に困り果ててBlog Hacksを読んだ気がする。
そのころはプログラミング言語を勉強するためには、
仕様を書いてある本を読みまくれ!なんて分かっていても手が出なかった。
とくにPerlの場合は「プログラミングPerl」を見ると、
あの分厚さと2冊に分かれているのとでノックアウトですよ。
ということで、CPANについてBlog Hacksを読んで軽く理解して、
「perl -MCPAN -e shell」した気がするな。
で、まず最初にBundle::CPANを入れろ!って英文で表示されたから、
「install Bundle::CPAN」してみた。訳も分からずに。
そしたら、あとはyes!yes!って言っているうちにモジュールが
インストールできたみたいだった。
このときに、「install モジュール名」って書くと
モジュールがインストールできるっぽいことに気がついた。
で、問題のXML::Simpleをインストールしようとしたら、
やっぱり怒られてしまうので困った。
仕方が無くメッセージを精読してみると、
必要なライブラリがインストールされていないことに気が付いた。
「ライブラリ名....no」とか表示されたあとエラーが出まくってたし。
ということで、ライブラリが足りないときには
apt-get installしたり、ソースからコンパイルして、
CPANモジュールが利用しているライブラリを入れるんだと気が付いた。
ライブラリが足りないときのエラーメッセージは、特徴的なので
そのまま検索エンジンに突っ込むと、どんなライブラリに関する
メッセージなのかが分かったりした。
あとは、CPANモジュールが足りないってエラーが出るときが
あるんだなと気が付いた。hoge::fugaがnot foundだよ見たいなエラーが
でたら、その見つかっていなモジュールをinstallしてみて、
そのモジュールもエラーを吐いたらそれを解決して・・・と
芋づる式にエラーを解決する方法を学習した。
ところが、そんなことではどうにもならない場合があることに気が付いた。
どういう場合かというと「必要なものはすべて揃っているけど、
テストがちゃんと動作しないから駄目」という場合だ。
こういうときのエラーメッセージも特徴的だから、
検索エンジンに突っ込んでみると、悩んでいる人は結構多い。
で、よく「force install」すれば解決すると書いてある。
そのころにforceっていう無理やりインストールするオプションが
あるんだなと分かった。
じゃ、見た目には必要なライブラリは揃っていて、
テストだけが上手くいかないときにはforceを使えば良いのかというと、
そういうものでも無いことに気が付いた。
キッカケは、他の人が「force insatall」するしかなかったという
モジュールを普通にインストールできたことを発見したときだった。
まったく同じOSで、こういうことが起きるということは、
私とその人でインストール済みのモジュールやライブラリが違うってこと。
つまり、見た目に良く分からない場合でも、apt-getで何かを
追加すれば解決できる問題も多そうだということに気が付いた。
このころには、テストを順番に読むのが面倒だと思いつつ、
ちゃんとエラーでこけっ放しのテストは読むようになった。
テストを読むと、エラーが絶対にでるから無視すれば良い場合と、
エラーが出るわけがないから出ていたら困る場合があることに気が付いた。
エラーが出るわけが無い場合は解決方法を探さなきゃいけなくて、
テストが悪いと分かった場合にはforce installすればいいって分かった。
いくつもモジュールのエラーを解決するうちに、
本当にお手上げのときもあることに気が付いた。
こういうときにはどうしたらいいんだろう。
解決方法は今のところ3パターンあって、以下のとおり。
- 環境ごとにパッケージ化されているPerlモジュールをインストールする
- とりあえずforce installする
- OSを最近のものに入れ替える。情報が多いOSに乗り換える。
どうしてもインストールできないモジュールを手軽にインストールするには
境ごとにパッケージ化されているPerlモジュールをインストすればいい。
Debianだと「hoge::fuga」モジュールは「libhoge-fuga-perl」という
名前になっていることが多い。とりあえずで解決するには丁度良い。
パッケージ化されているPerlモジュールがない場合もある。
本当に調べつくして、試しつくしたのならforce instalしてもいいかも。
私が最近困った事例としては、1年くらい試行錯誤して使っているうちに、
環境全体が汚れてしまって、ネットで調べても事例の見つからない
エラーが頻発するようになるという状況に陥ったこと。
自分ひとりだけが、そのエラーと戦っているような気分がしたときには、
一回OSを入れ替えて見ると良いかもしれない。
もちろん無駄だったときに、戻れるようにスペアマシンで試すんだけど。
私はDebian Sargeからtestingに乗り変えたら、嘘のようにエラーが起き
なくなった。
それまではmod_perl2のコンパイルがちゃんとできなくて悩んだりしてた。
CPANって分かりづらいよなーと思って、
頭にあることをツラツラかいてみたけれど、
分かったことはCPANを使うこと = エラーと積極的に戦うことなのかも。
CPANは便利だけど大変だよなー、ってことでPHPが流行したりするのは
なんとなく分かったりするけど、じゃあ何でPythonは流行らないんだろう。
ま、いいや。ともかくCPANは今でもよく分からないことが多い。
たぶん自分がモジュールの作者になると、見えてくることがあるんだろうな。
ということで、最近はモジュールの作者になりたいなと思ったりしている。
全然オチないっすよ。これ。もういいや。おしまい。
2007-03-02 Fri
perlのファイル演算子一覧
たまに使うけど、よく忘れるPerlの演算子一覧をメモ。
Perl を使おう! 第5回より。
| 演算子 | テスト |
| -e | ファイルやディレクトリが存在している |
| -z | ファイルが存在していてかつ大きさが0 |
| -s | ファイルやディレクトリが存在していてかつ大きさが0でない |
| -r | ファイルやディレクトリが読みだし可能 |
| -w | ファイルやディレクトリが書き込み可能 |
| -x | ファイルやディレクトリが実行可能 |
| -o | ファイルやディレクトリをユーザが所有 |
| -R | ファイルやディレクトリが実効ユーザでなく実ユーザにより読みだし可能< |
| -W | ファイルやディレクトリが実効ユーザでなく実ユーザにより書き込み可能 |
| -X | ファイルやディレクトリが実効ユーザでなく実ユーザにより実効可能 |
| -O | ファイルやディレクトリが実効ユーザでなく実ユーザにより所有 |
| -f | 普通のファイルである |
| -d | ディレクトリである |
| -l | シンボリックリンクである |
| -S | ソケットである |
| -p | 名前つきパイプである |
| -b | ブロック特殊デバイスである |
| -c | キャラクタ特殊デバイスである |
| -u | ファイルやディレクトリがsetuidされている |
| -g | ファイルやディレクトリがsetgidされている |
| -k | ファイルやディレクトリがstickyビットがセットされている |
| -t | このファイルハンドルに対して isatty()が真である |
| -T | テキストファイルである |
| -B | バイナリファイルである |
| -M | 最終更新からの日数 |
| -A | 最終アクセスからの日数 |
| -C | inodeの最終変更からの日数 |
-eして-fして-Wして、駄目なら-dして-Wして、とかやるときに必要。
2007-01-30 Tue
Lighttpd + Catalyst + FastCGIが動かない
Catalystのデバッグ用のサーバ「myapp_server.pl」は「-k -f」しないと、
いちいちIEをリロードしなきゃいけないことにブチ切れ。
もう、あれだ、FastCGIをデバグに使おう!と思った。
だけど、もー、どうにもこうにも動かないのである。
404エラーじゃ無くて、真っ白になってしまう。
Lighttpd-CatalystTechniqueのヘルパーを使ってみようとしたり、
使わないでやってみたりしてるんだけど、なんか駄目。
2時間やって駄目なので週末に再度やってみる。
それとは別の話として、環境を使い始めたころにいじった
わけの分からないことになってるところが影響して、
スムーズな環境構築ができてない場合が多くなってる気がする。
そろそろtestingで再インストールしようかな。
# 検索しても引っかからないエラー多すぎるんだよね。
# しかも、ほかの環境で再現しないんだよね。orz
2007-01-16 Tue
Net::Amazonが0.36になってECS4(AWS4)対応になってた
Net::Amazonがようやくアップデートした。
今回の一番大きな変化はECS4(AWS4)対応ってことみたい。
Net-Amazon-0.36
0.36 (01/09/2007)
(cb) Update the library to use AWS4 from AWS3. The changes
involved are quite deep. While I have strived to keep interfaces
the same that was not always possible. I am sure there are still
bugs to be had that need to be fixed.
でも、いろいろ変更があるみたいなので
0.35と0.36を取り替えて終了ってわけにはいかなさそうですね。
2007-01-07 Sun
DBICのリレーションシップ
やっぱり、DBIx::Class::Relationshipを読み直すことにした。
こういうのをちゃんと理解しておかないと足をすくわれるし。
ちょっとづつ書いたら、何日もかかった。ションボリ。
まずは前提となるデータ
こんな感じで、Authorテーブルと、Bookテーブルがあるとする。
------------------
1 | Fred | 30
2 | Joe | 32
ID | Author | Name
--------------------
1 | 1 | Rulers of the universe
2 | 1 | Rulers of the galaxy
リレーションシップなしの場合
もしもリレーションシップを使わないときに、Fredの書いた全ての本を取
り出すとしたら、以下のようになる。
my $fred = $schema->resultset('Author')->find({ Name => 'Fred' });
my $fredsbooks = $schema->resultset('Book')->search({ Author => $fred->ID });
2行書かなきゃいけなくて、理解はしやすいかも知れないけど面倒すぎ。
リレーションシップありの場合
リレーションシップを使えば1行ですむ。
今回の場合は「Author上でbooksという名前のhas_manyなリレーションシッ
プを宣言」しておけば、以下のようにできる。(細かいことは後)
my $fredsbooks = $schema->resultset('Author')->find({ Name => 'Fred' })->books;
確かに手間が半分以下になる。すごい。
リレーションシップって何??
各リレーションシップは、 テーブルのアイテムたちを構成する
DBIx::Class::Manual::Glossaryオブジェクト
の"Row"がもつ、アクセサメソッドをセットアップする。
RowオブジェクトはResultSetオブジェクトから返ってきた実際のデータ。
DBIx::Class::Manual::Glossaryオブジェクトの"ResultSet" より、
search_relatedを使って、リレーションシップたちは検索されることが可能になる。
ResultSetオブジェクトはテーブルオブジェクトのこと。データそのもの。
リレーションシップの利点
リレーションシップは
リストコンテキストでは、リレーションはRowオブジェクトたち
のリストを関連するクラスに返す。
スカラーコンテキストでは、JOINされたテーブルを表現する新し
いResultSetを返す。
だから、クエリ圧縮のためのリレーションの連鎖呼び出しができる。
従って、実際にデータベースにクエリが投げられるのは、
実際のアイテムのためのデータを検索する必要に迫られたときで、
それまでは一切無駄な時間を使わない。
例えば、以下のようにsearch_relatedメソッドを使うと、
以下のような1行のSQLを発効する。
my $cheapfredbooks = $schema->resultset('Author')->find({
Name => 'Fred',
})->books->search_related('prices', {
Price => { '<=' => '5.00' },
});
SELECT * FROM Author me LEFT JOIN Books books ON books.author = me.id LEFT JOIN Prices prices ON prices.book = books.id WHERE prices.Price <= 5.00
複数回のfetcheなしでいける。
つか、リレーションシップを記述する利点は豊富なヘルパーメソッド
このとき、どこかでpriceという名前で、Bookテーブルと値段の書いたテー
ブル(多分Priceテーブル)との間のリレーションを記述しておく必要がある。
リレーションシップを記述すると、search_relatedなどのヘルパーメソッドが使
えるようになる。
search_relatedメソッド以外にも、頻繁に使う基本的なヘルパーなメソッドが用意されている。
search_relatedメソッド以外の、頻繁に使う基本的なヘルパーメソッドは
DBIx::Class::Relationship::Baseにあるから、そっちを見る。
(add,regist,search,count,create,find,update,set,delete,add,remove・・・)
まー、何か大体あるなー。
で、実際のリレーションシップに使うメソッドを見てね。
ヘルパーメソッドどもの使い方について
すべてのヘルパーメソッドは以下のような引数を取得する。
_PACKAGE__>$method_name('relname', 'Foreign::Class', $cond, $attrs);
$condと$attrsはオプションだから、何も書かなくてもいい。
どうしても何かを書きたくて、かつ無記入と同じデフォルトの値を渡したいときは、
undefを渡せばいいよ。
ヘルパーメソッドはさておき、リレーションの記述方法
実際にリレーションを記述するのは、テーブルスキーマを記述するクラス。
例えば、DB用のスキーマと、テーブルのスキーマを用意する。
package My::DBIC::Schema;
use strict;
our $VERSION = '0.01';
use warnings;
use base qw/DBIx::Class::Schema/;
__PACKAGE__->connection('dbi:mysql:testapp', 'id', 'pass');
__PACKAGE__->load_classes(qw/Books Authors ISBN/);
1;
MySQLにtestappという名前のDBをcreateした状態。
idとpassには接続に必要なものを書く。
つか、いい加減だからコピペしても動かないと思う。
さらに、テーブルのスキーマ。
package My::DBIC::Schema::Book;
use strict;
our $VERSION = '0.01';
use warnings;
use base qw/DBIx::Class/;
__PACKAGE__->load_components(qw/PK::Auto Core/);
__PACKAGE__->table('book');
__PACKAGE__->add_columns(qw/id author name/);
__PACKAGE__->set_primary_key('id');
1;
__END__
package My::DBIC::Schema::Author;
use strict;
our $VERSION = '0.01';
use warnings;
use base qw/DBIx::Class/;
__PACKAGE__->load_components(qw/PK::Auto Core/);
__PACKAGE__->table('author');
__PACKAGE__->add_columns(qw/id name age/);
__PACKAGE__->set_primary_key('id');
1;
__END__
まー、多分こんな感じ。
説明とスキーマ内のテーブルとかアイテムの名前が違うけど、そこはそれ。
何書いているのか良く分からない人は、WEB-DBマガジンVol.36のnaoyaさ
んの連載を見ると、へえ、と分かると思います。
これらのものが少なくともある状態で、以下につづく。
has_one
Arguments: $accessor_name, $related_class,$foreign_key_column|$cond?, $attr?
引数:アクセサ名、関連付け対象のクラス名が必須。必要ならその他の引数も。
どこかにBookテーブルのidカラム(PK)と対応付けられている、
ISBNテーブルがあって、確実にBookとISBNが1対1対応すると分かっている
ときの例は以下のような感じ。My::DBIC::Schema::ISBNは省略。
package My::DBIC::Schema::Book; ・・・ __PACKAGE__->has_one(isbn => 'My::DBIC::Schema::ISBN');
My::DBIC::Schema::Bookに追記するってことですよ。
こういうリレーションシップを書いておくと、
isbnを呼び出してResultSetを得たり、ヘルパーメソッドを使えたりする。
あるクラスと他のクラスの1対1のリレーションシップを作ったことになる。
my $schema = My::DBIC::Schema->connect;
my $obj = $schema->resultset('Book')->find(1);
my $isbn_obj = $obj->isbn; # to get the ISBN object
この場合、スカラーコンテキストなのでResultSet(データ)が返ってくる。
返ってきたResultSetは、BookテーブルとISBNテーブルがINNER JOINされ
たもの。
JOINする際に「対応するオブジェクトが必ずある」という暗黙の了解がな
い場合は、might_haveを使うと良い。
might_haveの場合には、LEFT JOINされたResultSetが返ってくる。
has_oneとmight_haveの違いは、それだけ。
INNER JOINの場合は、対応関係が取れないデータは無視するし、
LEFT JOINの場合には対応関係が取れない場合に、対応先として、
とりあえずnullを挿入してJOINしてくれる。
JOINするときに使われるキーについては、might_haveの説明中に書く。
ちなみに、上のリレーションシップの場合は、
My::DBIC::Schema::ISBNのisbnカラムか、My::DBIC::Schema::ISBNのPKが、
My::DBIC::Schema::BookのPKと対応していると考えられる。
might_have
あー、えーと、Pseudonymテーブルが出てきますけど記述は省略。
Arguments: $accessor_name, $related_class,$foreign_key_column|$cond?, $attr?
引数:アクセサ名、関連付け対象のクラス名が必須。必要ならその他の引数も。
package My::DBIC::Schema::Author; ・・・ __PACKAGE__->might_have(pseudonym => 'My::DBIC::Schema::Pseudonym');
このようなリレーションを記述することで、以下のようにできる。
my $schema = My::DBIC::Schema->connect;
my $obj = $schema->resultset('Author')->find(1);
my $pname = $obj->pseudonym; # to get the Pseudonym object
で、JOINするときのキーが一体何なのか。
これが知りたくて英語ドキュメントを読み直したんだけど、
ちゃんと書いてありましたよ。
JOINするときのキーは何なのか
My::DBIC::Schema::Author->might_have(pseudonym =>'My::DBIC::Schema::Pseudonym')
上の例のMy::DBIC::Schema::Authorへの記述は、
クラスに対する任意の1対1のリレーションシップを作る。
これはhas_oneとmight_haveで共通のこと。
「Authorはmight_haveだ。Pseudonymを。」という関係。
つまりAuthorがPseudonymを所有している。
PseudonymがAuthorを所有するかなー?と思うので、
この場合、AuthorはPseudonymのPKを知らないけれど、
PseudonymはAuthorのPKを知っている状態ということになる。
まー、もちろん、AuthorがPseudonymのPKを知っていて、
互いに所有しあっていても問題はない。
ポイントは所有される側が、所有する側のPKを知っているか、
ということだろう。
これって、何か哲学的だなー。
例えば主人と犬がいて、犬は主人のPKを知らなきゃいけないけれど、
主人は犬のPKを知っていても知らなくてもいいってことだよなー。
ふかいー。子供が泣くから親は子を育てるんですねー。
あ、脱線した。
リレーションシップは標準ではアクセサ名(例、pseudonym)を、
関連付けされたクラス(例、My::DBIC::Schema::Pseudonym)中の外部キー
として、JOINを解決するために使う。
リレーションの記述の3つめの引数は、$foreign_key_columnか$condだが
例外は、関連付けされたクラスに$foreign_key_columnに明記されたカラムが
ある場合や、$condがJOIN条件を示すハッシュへの参照を示す場合だ。
リレーションシップは
- 関連付けされたクラスに$foreign_key_column(外部キーのカラム)と明記されたカラムがあるか
- JOIN条件を示すハッシュ$condがあるか
を調べて、JOINの対応を解決しようとする。
そもそも$foreign_key_columnか$condがなければ、
- 関連付けされたクラスに、アクセサ名と同じ名前のカラムはあるか
を調べてくれる。もしカラムがあればJOIN時につかわれる。
それでも駄目なら、2つのテーブルはPKを共有していると見なすようだ。
なるほどねー。あとで試してみよう。やっと分かったよー。
つまり、上述のAuthorとPseudonymのリレーションシップでは、
AuthorにPseudonym関連の記述がないことは分かっているので、
PseudonymのpseudonymカラムかPKが、AuthorのPKと一致していないと、
期待通りの結果を得られないことがわかる。
PseudonymのauthorというカラムにAuthorのPKが入っているときには、
以下のように書いてあげれば、期待通りのJOINの解決がおこなわれる。
これが、$foreign_key_columnの設定。
この場合、PseudonymのauthorカラムをJOINに使う。
My::DBIC::Schema::Author->might_have( pseudonym => 'My::DBIC::Schema::Pseudonym', 'author' );
さもなくば、こう書く。これがJOIN条件を示すハッシュ$cond。
My::DBIC::Schema::Author->might_have( pseudonym =>
'My::DBIC::Schema::Pseudonym',
{ 'foreign.author' => 'self.author' } );
この場合、foreign(My::DBIC::Schema::Pseudonym)のauthorカラムと
self(My::DBIC::Schema::Author)のauthorカラムをJOINの解決に使ってくれる。
JOINの解決に呼び出し側のPKを使わない場合はこれだね。
結局has_oneとmight_haveとbelongs_toは、それぞれ理解すると理解が深
まるので、上を見たり下をみたりするといいかも。
belongs_to
では、belongs_to。基本はhas_oneやmight_haveと同じ。
Arguments: $accessor_name, $related_class,$foreign_key_column|$cond?, $attr?
引数:アクセサ名、関連付け対象のクラス名が必須。必要ならその他の引数も。
# in a Book class (where Author has many Books) My::DBIC::Schema::Book->belongs_to( author => 'My::DBIC::Schema::Author' ); my $author_obj = $obj->author; # get author object $obj->author( $new_author_obj ); # set author object
「Bookは所有されている。Authorに。」という関係。
AuthorがBookの親であるという関係ですね。
AuthorがBookのPKをどのカラムにも持っていないときに使う。
つまり呼び出される側が呼び出す側のPKを持っていない場合が、
belongs_toとなる。
呼ぶ側のクラスが呼ぶ側のクラス自身のカラムの一つ(または複数)に、
呼ばれる側である外部クラスのプライマリキー(PK)を保存している、とい
うリレーションシップを作る。
上の例の場合、
呼ぶ側クラスから見た外部クラスは「My::DBIC::Schema::Author」で、
呼ぶクラス「My::DBIC::Schema::Book」は、コラムのどこかにAuthorのPK
をもっているということだ。
ふむふむ。
上述の例だと、$foreign_key_columnや$condが無いので、
Bookのauthorカラムを使おうとするわけだ。
ちなみにbelongs_toは1対1、1対多、多対多の関係のどれでも使われる。
has_oneやmight_haveは必ず1対1ね。
$foreign_key_columnや$condの使い方は同じ。
My::DBIC::Schema::Book->belongs_to( author=> 'My::DBIC::Schema::Author',
{ 'foreign.author' => 'self.author' } );
4つめの引数$attって何?
$attの説明をすっ飛ばしてきた。じゃあ、理解してみよう。
has_oneやmight_haveは、そのようなリレーションシップにおけるオブジェ
クト(JOINされたデータ)を作るためにあるんだけれど、
そのオブジェクトにdeleteしたりupdateしたりしたときに、
標準では関連付けされた基のオブジェクトもdeleteされたりupdateされ
たりする。これが嫌なときは$attを使う。
関連づけされた基のオブジェクトへの作用を切るには以下のようにする。
My::DBIC::Schema::Author->might_have( pseudonym =>
'My::DBIC::Schema::Pseudonym',
'author', {cascade_delete => 0} );
こうすることで、DBレベルのdaleteやupdateの制約を無効化できる。へえ。
belongs_toの$attではJOINの方法を指定できる。
どうもbelongs_toの標準はINNER_JOINのようだ。
そうすると、$obj->authorして、Bookのauthorカラムを見たときに、
Authorのauthorカラムと対応するものがないときに、
その対応するものがないauthorカラムの要素はJOIN時に無視される。
そうではなくて、Bookのauthorカラムに対応する要素がないなら、
対応要素の代わりにNULLをいれて欲しい場合もある。
そんな時は、以下のようにしてleft_joinだよ、と思えてあげればいい。
# in a Book class (where Author has_many Books)
__PACKAGE__->belongs_to(author => 'My::DBIC::Schema::Author',
'author', {join_type => 'left'});
また、belongs_toでは標準で「cascade_delete => 0」になっている。
なので、DBレベルのdaleteやupdateの制約を有効にしたければ、
「cascade_delete => 1」と指定してあげればいい。
has_many
はぁ、疲れてきた。has_manyか。
Arguments: $accessor_name, $related_class,$foreign_key_column|$cond?, $attr?
引数:アクセサ名、関連付け対象のクラス名が必須。必要ならその他の引数も。
has_oneじゃなく、1対多のhas_many。
「こいつはもってる。たくさんのあれを。」な関係。
今回は著者と本の関係。一人の著者が沢山の著書をもってる場合ですね。
記述はhas_oneとかの時と、そんなに変わっていない。
# in an Author class (where Author has_many Books) My::DBIC::Schema::Author->has_many(books => 'My::DBIC::Schema::Book', 'author');
Authorから見て、複数のbookを持っているんだから、
直感的にbooksという名前のアクセサ名にしたい。
Author - has_many - booksね。
でも、そうするとbooksカラムなんて無いから、
ちゃんと$foreign_key_columnを指定する必要がある。
上述の場合は、BookのauthorカラムとAuthorのPKが対応してる。
もちろん、$foreign_key_columnや$condが無いときには、
アクセサ名を使って呼ばれたクラス(例だとBook)のカラムを探す。
なるほどね。
has_manyなリレーションシップを作ると、
3つのメソッドが作られて、それらを使えるようになる。
上述の例だと、以下の3つが作られる。
- books()
- books_rs()
- add_to_books()
要するに、
- $accessor_name()
- $accessor_name + _rs()
- add_to_ + $accessor_name()
の3つが作られる。
まず、例文を示す。
# in an Author class (where Author has_many Books)
My::DBIC::Schema::Author->has_many(books =>
'My::DBIC::Schema::Book', 'author');
my $booklist = $obj->books;
my $booklist = $obj->books({
name => { LIKE => '%macaroni%' },
{ prefetch => [qw/book/],
});
my @book_objs = $obj->books;
my $books_rs = $obj->books;
( $books_rs ) = $obj->books_rs;
$obj->add_to_books(\%col_data);
3つのメソッドを使っている。
リレーションシップで返ってくるオブジェクトは、
スカラーコンテキストの場合ResultSetだと分かっているので、
books()の使い方については割愛。
# だって、今はリレーションシップが分からないんだもん。
さらに、books_rs()は、単純にResultSetを返してくれる。
ただ、ポイントなのはスカラーコンテキストでも、
リストコンテキストでも、お構い無しにResultSetを返す。
add_to_books()については、詳しくはDBIx::Class::Relationship::Base
を参照してくれと書いてある。
新しいRowアイテムを追加するためにあるメソッドのようだ。
そのため、has_manyは標準ではDBレベルのdaleteやupdateの制約が
有効になっている。無効にしたければ$attに「cascade_delete => 0」
を入れておけばいい。
ちなみに、add_to_の例はこんな感じ。
my $role = $schema->resultset('Role')->find(1);
$actor->add_to_roles($role);
# creates a My::DBIC::Schema::ActorRoles linking table row object
$actor->add_to_roles({ name => 'lead' }, { salary => 15_000_000 });
# creates a new My::DBIC::Schema::Role row object and the linking table
# object with an extra column in the link
あー、なるほどねー。だ。
many_to_many
最後だ最後。many_to_manyいってみよう。
Arguments: $accessor_name, $link_rel_name, $foreign_rel_name, $attr?
引数:アクセサ名、リンクリレーションシップ名、外部リレーションシッ
プ名が必須。必要ならその他の引数も。
どんなときがmany_to_manyなのか。
それはマルチユーザなブックマークとかを考えるといいかも。
複数のユーザと複数のエントリがあって
あるユーザの行に複数のエントリの行が対応していて、
また、複数のユーザの行に、あるエントリの行が対応している。
そんなのをイメージすると、many_to_manyって必要だなと分かる。
実際のところ、このmany_to_manyな関係は例えばBookとAuthorのような、
2つのテーブルがあれば使えるわけではなく、
もう1つ中間テーブルのようなものが必要になる。
UserテーブルとEntryテーブルのmany_to_manyを表現するには、
Bookmarkテーブルも必要ってことですね。へえ。
丁度良いので、WEB-DBマガジンVol,36のBookmarkアプリの
スキーマを使って考えてみようかな。
create table user(
id int unsigned auto_increment primary key,
name varchar(32),
key (name)
) TYPE = MyISAM DEFAULT CHARSET=utf8;
create table entry(
id int unsigned auto_increment primary key,
url varchar(255) binary unique,
title varchar(255),
created_on datetime,
key (url)
) TYPE = MyISAM DEFAULT CHARSET=utf8;
create table bookmark(
user_id int unsigned,
entry_id int unsigned,
comment text,
created_on datetime,
primary key(user_id, entry_id)
) TYPE = MyISAM DEFAULT CHARSET=utf8;
あー、ふーん。なるほど。
で、many_to_manyを使うまえにhas_manyな関係を記述する。
・userとbookmarkの関係
package Bookmark::Schema::User;
use strict;
our $VERSION = '0.01';
use warnings;
use base qw/DBIx::Class/;
__PACKAGE__->load_components(qw/PK::Auto Core/);
__PACKAGE__->table('user');
__PACKAGE__->add_columns(qw/id name/);
__PACKAGE__->set_primary_key('id');
__PACKAGE__->has_many(
bookmarks=>'Bookmark::Schema::Bookmark',{
'foreign.user_id'=>'self.id'
}
);
1;
・entryとbookmarkの関係
package Bookmark::Schema::Entry;
use strict;
our $VERSION = '0.01';
use warnings;
use base qw/DBIx::Class/;
__PACKAGE__->load_components(qw/PK::Auto Core/);
__PACKAGE__->table('entry');
__PACKAGE__->add_columns(qw/id url title created_on/);
__PACKAGE__->set_primary_key('id');
__PACKAGE__->has_many(
bookmarks=>'Bookmark::Schema::Bookmark',{
'foreign.entry_id'=>'self.id'
}
);
1;
・bookmarkとentryの関係、と、bookmarkとuserの関係
package Bookmark::Schema::Bookmark;
use strict;
our $VERSION = '0.01';
use warnings;
use base qw/DBIx::Class/;
__PACKAGE__->load_components(qw/PK::Auto Core/);
__PACKAGE__->table('bookmark');
__PACKAGE__->add_columns(qw/user_id entry_id comment/);
__PACKAGE__->set_primary_key('user_id', 'entry_id');
__PACKAGE__->belongs_to(
entry=>'Bookmark::Schema::Entry',{
'foreign.id'=>'self.entry_id'
}
);
__PACKAGE__->belongs_to(
user=>'Bookmark::Schema::User',{
'foreign.id'=>'self.user_id'
}
);
1;
で、ここからmany_to_manyにしてみる。
あんまり意味がありませんが・・。
いじくるのは、Bookmark::Schema::EntryとBookmark::Schema::User。
・userとbookmarkの関係にmany_to_manyを追記
package Bookmark::Schema::User;
use strict;
our $VERSION = '0.01';
use warnings;
use base qw/DBIx::Class/;
__PACKAGE__->load_components(qw/PK::Auto Core/);
__PACKAGE__->table('user');
__PACKAGE__->add_columns(qw/id name/);
__PACKAGE__->set_primary_key('id');
__PACKAGE__->has_many(
bookmarks=>'Bookmark::Schema::Bookmark',{
'foreign.user_id'=>'self.id'
}
);
__PACKAGE__->many_to_many(
entries=>'bookmarks', 'entry'
);
1;
・entryとbookmarkの関係にmany_to_manyを追記
package Bookmark::Schema::Entry;
use strict;
our $VERSION = '0.01';
use warnings;
use base qw/DBIx::Class/;
__PACKAGE__->load_components(qw/PK::Auto Core/);
__PACKAGE__->table('entry');
__PACKAGE__->add_columns(qw/id url title created_on/);
__PACKAGE__->set_primary_key('id');
__PACKAGE__->has_many(
bookmarks=>'Bookmark::Schema::Bookmark',{
'foreign.entry_id'=>'self.id'
}
);
__PACKAGE__->many_to_many(
'users'=>'bookmarks', 'user'
);
1;
Bookmark::Schema::Bookmarkが、Bookmark::Schema::Entryと
Bookmark::Schema::Userの間を取り持ってくれている。
Bookmark::Schema::Userではentriesというリレーションシップを作って、
Bookmark::Schema::Userのhas_manyで記述したbookmarks経由で、
Bookmark::Schema::Bookmarkのuserリレーションシップを呼ぶ。
Bookmark::Schema::Entryではusersというリレーションシップを作って、
Bookmark::Schema::Entryのhas_manyで記述したbookmarks経由で、
Bookmark::Schema::Bookmarkのentryリレーションシップを呼ぶ。
こうすることで、「B::S::Entryから、あるエントリに紐づく複数のユーザ」や
「B::S::Userから、あるユーザに紐づく複数のエントリ」を取得できる。
ああ、まー使えるかも。
many_to_manyでは、アクセサは2つのリレーションシップのようなものをつくり
ともかくアクセサはhas_manyのように、ResultSetやオブジェクトのリス
トを返す。
上の例のBookmarkクラスのように、many_to_manyな関係を作りたい
2つのテーブルの間を取り持つクラスをリンクテーブルクラスと言う。
Bookmark::Schema::Entryの例に着目して、many_to_manyの記述を見る。
package Bookmark::Schema::Entry;
・・・
__PACKAGE__->has_many(
bookmarks=>'Bookmark::Schema::Bookmark',{
'foreign.entry_id'=>'self.id'
}
);
__PACKAGE__->many_to_many(
'users'=>'bookmarks', 'user'
);
package Bookmark::Schema::Bookmark;
・・・・
__PACKAGE__->belongs_to(
user=>'Bookmark::Schema::User',{
'foreign.id'=>'self.user_id'
}
);
Bookmark::Schema::Entryを見る。Bookmark::Schema::Entryからの視点で
は、Bookmark::Schema::Bookmarkがリンクテーブルクラスと呼ばれ
Bookmark::Schema::Bookmark::Schema::Userは外部クラスと呼ばれる。
many_to_manyだけ、他のリレーションシップと引数が違って
引数 = ($accessor_name, $link_rel_name, $foreign_rel_name, $attr?)
だった。
アクセサ名は今までと同じ。
$link_rel_nameパラメタは、many_to_manyを記述しているクラスのテーブ
ル(例ではBookmark::Schema::Entry)からリンクテーブル(例では、
Bookmark::Schema::Bookmark)へのhas_manyなリレーションシップのアク
セサ名を記述する。
$foreign_rel_nameパラメタには、リンクテーブルから外部テーブルへの
belongs_toなリレーションシップのアクセサ名を記述する。
many_to_manyを使うためには、データを格納している外部テーブル(オリ
ジナルテーブルとも呼ぶ)からリンクテーブルへのリレーションシップと、
リンクテーブルからmany_to_manyを記述したテーブル(エンドテーブルと
も呼ぶ) へのリレーションシップが必要となる。
many_to_manyリレーションシップを呼ぶと合計3つのリレーションシップ
を使うことになる。
many_to_manyリレーションシップでも、
has_manyと同じような感じで3つのメソッドが作られる。
上の例では以下の3つのメソッドがつくられる。
- users();
- add_to_users();
- set_users();
つまり、
- $accessor_name();
- add_to_ + $accessor_name();
- set_ + $accessor_name();
が作られる。使い方は
・add_to_
Arguments: ($foreign_vals | $obj), $link_vals?
$actor->add_to_roles({ name => 'lead' }, { salary => 15_000_000});
# creates a new My::DBIC::Schema::Role row object and the linking table
# object with an extra column in the link
・set_
Arguments: (\@hashrefs | \@objs)
my $actor = $schema->resultset('Actor')->find(1);
my @roles = $schema->resultset('Role')->search({ role =>
{ '-in' -> ['Fred', 'Barney'] } } );
$actor->set_roles(\@roles);
# Replaces all of $actor's previous roles with the two named
add_to_は追加したオブジェクトからリンクテーブルオブジェクトが作ら
れる。追加したリンクテーブルのカラムは$link_valsで指定できる。
set_は、既存のリンクテーブルオブジェクトをset_で与えたオブジェクト
を入れ替える。既存のリンク関係は全部破棄されて、新しいリンクが作ら
れる。
詳しくはDBIx::Class::Relationship::Base
はー、長い。一応自分が使ったお試しスクリプトも貼っておく。
#!/usr/bin/perl
use strict;
use warnings;
use lib qw(./lib);
use Bookmark::Schema;
my $schema = Bookmark::Schema->connect;
$schema->storage->debug(1);
# 完全に削除
$schema->resultset('User')->search( {} )->delete;
$schema->resultset('Bookmark')->search( {} )->delete;
$schema->resultset('Entry')->search( {} )->delete;
my $u_rs = $schema->resultset('User');
my $b_rs = $schema->resultset('Bookmark');
my $e_rs = $schema->resultset('Entry');
$u_rs->create( { name => 'bw4' } );
$u_rs->create( { name => 'satou' } );
$e_rs->create(
{ url =>
'http://gigazine.net/index.php?/news/comments/20070106_firefox_revenue/',
title => 'firefox',
}
);
$e_rs->create(
{ url => 'http://www.popxpop.com/archives/2007/01/5firefox.html',
title => 'firefox',
}
);
my $users_rs = $u_rs->search( {} ); # get ResultSet
while ( my $user = $users_rs->next ) { # use iterator(search once)
print $user->name, ": search\n";
}
my $bw_users_rs = $u_rs->search_like( { name => 'bw%' } ); #LIKE get ResultSet
while ( my $user = $bw_users_rs->next ) { # use iterator(search once)
print $user->name, ": search like bw\n";
}
my $tmp_user;
$tmp_user = $u_rs->find( { name => 'satou' } ); # get Bookmark::Schema::User
# $bookmarks will be Bookmark::Schema::Bookmark
my $bookmarks = $tmp_user->bookmarks(); # has_many
while ( my $bm = $bookmarks->next ) { # use iterator(search once)
print $bm->comment, ": entry->bookmarks()\n";
}
$bookmarks = $tmp_user->bookmarks_rs();
while ( my $bm = $bookmarks->next ) { # use iterator(search once)
print $bm->comment, ": entry->bookmarks_rs()\n";
}
# has_many
$bookmarks = $tmp_user->add_to_bookmarks(
{ entry_id => 1,
comment => 'hahaha',
}
);
# has_many
$bookmarks = $tmp_user->add_to_bookmarks(
{ entry_id => 2,
comment => 'fufufu',
}
);
# get Bookmark::Schema::Bookmark
my $bookmark = $tmp_user->search_related( 'bookmarks', { entry_id => 2 }, )->first;
my $entry = $bookmark->entry; # get Bookmark::Schema::Entry
# get ResultSet
my $bookmark_rs = $entry->search_related( 'bookmarks', { entry_id => 2 }, );
while ( my $bm = $bookmark_rs->next ) { # use iterator(search once)
print $bm->comment, ": search related\n";
}
my $entries_rs = $tmp_user->entries();
while ( my $ent = $entries_rs->next ) { # use iterator(search once)
print $ent->url, ": entries()\n";
}
$tmp_user->add_to_entries(
{ url => 'http://www.popxpop.com/archives/2007/01/5firefox.xml',
title => 'firefox!!!',
}
);
$entries_rs = $tmp_user->entries();
while ( my $ent = $entries_rs->next ) { # use iterator(search once)
print $ent->url, ": entries()\n";
}
my @ent_arr = $e_rs->search_like( { title => '%!%' } );
$tmp_user->set_entries( \@ent_arr );
$tmp_user->add_to_entries(
{ url => 'http://overlasting.dyndns.org/', title => 'my blog', } );
$entries_rs = $tmp_user->entries();
while ( my $ent = $entries_rs->next ) { # use iterator(search once)
print $ent->url, ": entries()\n";
}
書き始めたときは、あとで読み返すかな?と思ったけど、
記事にしちゃうと理解がおわっていて、後で見返すか不安。ま、いいか。
あと、書き忘れたけど、has(have)とbelongsは表裏一体の関係なので、
片方向からだけでなく、双方向になるように両方とも記述しておくと、
あとで楽ですよっていうか、双方向にするような慣習があるみたい。
はっきりしないところはDBICよりもRuby on Railsの資料を読んだほうが
わかったりするかもしれませんね。
[2007-01-03-4] DBICのリレーションが良くわからないのでメモ - 1対多
[2007-01-03-3] DBICのリレーションが良くわからないのでメモ - 1対1
[-] 3
2007-01-03 Wed
DBICのリレーションが良くわからないのでメモ - 1対多
[2007-01-08]:追記
[2007-01-07-0]で、DBICのリレーションシップについてのエントリを
書きました。以下は非常にいい加減なので[2007-01-07-1]をどうぞ。
よく分からない1対多のhas_manyと、belongs_toの使い方を理解したい。
引き続き、以下の文献をグルグル読みながら理解してみる。。
101号室より愛をこめて: [DBIx::Class][DBIC][perl] DBIx::Classのリレーション
Perl/DBIC - Nekokak's core dump
DBIx::Class::Manual::Cookbook
DBIx::Class::Relationship
カエルチュウイホウ - DBICで多対多の設定を
カエルチュウイホウ - DBICで多対多
以下に出てくるコードとかは参照先を書いてませんが、
上の参考記事のどこかから持ってきました。ありがとうございます。
Userテーブルと本テーブルがあって、Userが本を各自多数持っている状態を考えると、いい感じかな。
基本的なことは、1対1と同じ。
user_id text primary key,
password text,
....
);
CREATE TABLE Book (
book_id integer primary key,
user_id text,
name text,
author text,
....
);
こんなときに、
や
のように記述できる。
前者は$user->booksで、ユーザが持っている本のリストを得られて、
後者は$book->user_idで、着目している本を持っているユーザのリストを得られるのだ。
うーん、なんか不十分な気がするので、もうちょっと例を探そうかな。
いや、ドキュメント中心にちゃんと読もう。
2007-01-03 Wed
DBICのリレーションが良くわからないのでメモ - 1対1
[2007-01-08]:追記
[2007-01-07-1]で、DBICのリレーションシップについてのエントリを
書きました。以下は非常にいい加減なので[2007-01-07-1]をどうぞ。
よく分からないというか、has_oneとmight_haveとbelong_toの明確な違い
が分からなくて、どうすれば一生間違いなく理解できるかなと、
これらを見て、理解することから始めた。
101号室より愛をこめて: [DBIx::Class][DBIC][perl] DBIx::Classのリレーション
Perl/DBIC - Nekokak's core dump
DBIx::Class::Manual::Cookbook
DBIx::Class::Relationship
カエルチュウイホウ - DBICで多対多の設定を
カエルチュウイホウ - DBICで多対多
以下に出てくるコードとかは参照先を書いてませんが、
上の参考記事のどこかから持ってきました。ありがとうございます。
リレーションはテーブル間にリファレンスを張るようなもの。
JOINでテーブルをくっつけてくれる。
has_oneとmight_hasとbelongs_toはテーブルAの行とBの行の間に1:1対応の関係
has_one : INNER JOIN(一致する行のみを持ってくる)
might_have : LEFT JOIN(一致しない行には、片側にNULLを付けて持ってくる)
user_id text primary key,
password text,
....
);
CREATE TABLE Profile (
user_id text primary key,
name text,
mail text,
....
);
こういう風に互いに相手のprimary keyがどこかに入っているときには、
has oneでリレーションを記述できる。
や
のようにできる。
こんな風にリレーションを記述しておくと、$user->profileみたいにアクセスできる。
この場合Primary Keyを使ってJoinしてる。
もちろん、相手のPrimary Keyが自分のPrimary Keyじゃなくても良い。
以下のように、Primary Keyが共有じゃないけど、普通のカラムには持っているときには、
user_id text primary key,
profile_id text,
password text,
....
);
CREATE TABLE Profile (
profile_id text primary key,
user_id text,
name text,
mail text,
....
);
や
のようにできる。
つまり、has_oneはINNE RJOINする相手のテーブルが、自分のPrimary Keyを
Primary Keyか普通のカラムのどれかに持っていることをあらわしている。
might_haveはLEFT JOINする以外はhas_oneと同じ。
でも、都合よく相手が自分のPrimary Keyを持っていないときもある。
user_id text primary key,
password text,
....
);
CREATE TABLE Profile (
profile_id text primary key,
user_id text,
name text,
mail text,
....
);
このときUserから見ると、ProfileはUserのPrimary Keyをもっている。
けど、Profileから見ると、UserはProfileのPrimary Keyをもっていない。
なので、
これはできそうだけど、逆は???って感じ。
こういうときにbelongs_toを使う。
使い方はこんな感じ。
Profileは、Userのアクセサ名テーブルか、
UserのPrimary Keyに従ってJOINするよ、という解釈ができる。




