+VERSION-0.05000での記述。http://search.cpan.org/~mstrout/DBIx-Class/
+ドキュメントも当初に比べれば増えてきたし、そっち見たほうがよかばい。
+まあ以下は簡単なまとめで。一通り使えるくらいは書きたい。
+{{word '''このサイトはWikiなので途中途中に色々追加したり修正したりしますからご注意を''',red,medium}}
+
+!!!DBIx::Class::Schemaを使ってみる
+これからDBICではSchemaメインらしい。
+
+使うテーブル作成SQL
+
+{{code SQL,4,
+create table user (
+ id int(10) NOT NULL auto_increment,
+ name varchar(256) NOT NULL,
+ PRIMARY KEY (id)
+) ENGINE = InnoDB;
+}}
+
+!!アプリで使うDBスキーマの定義
+
+下の例ではUserテーブルをこのアプリケーションで使うよって感じかね。
+
+{{code Perl,4,
+package Neko::Schema;
+
+use strict;
+use warnings;
+use base 'DBIx::Class::Schema';
+
+__PACKAGE__->load_classes(qw/User/);
+
+1;
+}}
+
+load_classesにテーブル指定しないと、Neko::Schema::*が指定されたとみなす。
+
+{{code Perl,4,
+__PACKAGE__->load_classes();
+}}
+
+複数に分かれたスキーマを扱いたい場合はこんな感じ。
+
+{{code Perl,4,
+__PACKAGE__->load_classes(
+ {
+ 'Neko::Schema' => qw/ User /,
+ 'Neko::OtherSchema' => qw/ Item /
+ }
+);
+}}
+
+!!テーブルにマッピングさせるモジュールの定義
+
+{{code Perl,4,
+package Neko::Schema::User;
+
+use strict;
+use warnings;
+use base 'DBIx::Class';
+
+__PACKAGE__->load_components(qw/ PK::Auto::MySQL Core/);
+__PACKAGE__->table('user');
+__PACKAGE__->add_columns(qw/id name/);
+__PACKAGE__->set_primary_key('id');
+
+1;
+}}
+
+!!データのinsert/select/update/delete
+
+{{code Perl,4,
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+use Neko::Schema;
+
+my $schema = Neko::Schema->connect('dbi:mysql:nekodb','nekokak','******');
+
+# insert
+$schema->resultset('User')->create({id => 1, name => 'nekokak'});
+
+# select
+my $user = $schema->resultset('User')->find(1);
+print $user->id,"\n";
+print $user->name,"\n";
+
+# update
+$user->name('nomaneko');
+$user->update;
+
+# select
+$user = $schema->resultset('User')->find(1);
+print $user->id,"\n";
+print $user->name,"\n";
+
+# delete
+$user->delete;
+}}
+
+これでUserテーブルに対して操作可能でつ。
+
+!!searchメソッドで
+
+findはプライマリキーに対してのselectなので、searchメソッドで
+検索条件を指定してみる。
+
+{{code Perl,4,
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+use Neko::Schema;
+
+my $schema = Neko::Schema->connect('dbi:mysql:nekodb','nekokak','******');
+
+my $it = $schema->resultset('User')->search({name => 'nekokak'});
+
+while ( my $user = $it->next ) {
+ print $user->id,':',$user->name,"\n";
+}
+}}
+
+イテレータで受け取った場合は、nextメソッドとかfirstメソッドでデータを取り出す。
+CDBIと同じだけど、返りをスカラーで受け取るとイテレータに、配列で受け取ると
+配列にしたデータを返してくれる。
+
+{{code Perl,4,
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+use Neko::Schema;
+
+my $schema = Neko::Schema->connect('dbi:mysql:nekodb','nekokak','******');
+
+#my $it = $schema->resultset('User')->search({name => 'nekokak'});
+my @no_it = $schema->resultset('User')->search({name => 'nekokak'});
+
+for my $user ( @no_it ) {
+ print $user->id,':',$user->name,"\n";
+}
+}}
+
+でも、これは必要ないデータまでとってきてくれたりするので、イテレータ使うべし。
+
+!!コネクションを分ける
+
+複数のコネクションが必要なら、
+{{code Perl,4,
+my $schema = Neko::Schema->connect('dbi:mysql:nekodb','nekokak','******');
+my $schema2 = Neko::Schema->connect('dbi:mysql:nekodb','nekokak','******');
+}}
+と、するだけぽい。
+
+!!searchメソッドで色々
+
+例えばidが5以上のデータをとりたいな〜って思った時なんか、
+{{code Perl,4,
+my $it = $schema->resultset('User')->search({id => { '>' => 5}});
+}}
+
+
+例えばidが5以上でnameがnomanekoのデータがほしいなぁと思ったとき、
+{{code Perl,4,
+my $it = $schema->resultset('User')->search({id => { '>' => 5},name => 'nomaneko'});
+}}
+
+例えばidが1,3,5,7,9のデータがほしいなぁと思ったとき、
+{{code Perl,4,
+my $it = $schema->resultset('User')->search({id => [1,3,5,7,9]});
+}}
+
+==これ、ちゃんとid in (1,3,5,7,9)にしてくれるっぽい。==
+してくれないみたい。。
+
+{{code SQL,4,
+ SELECT me.id, me.name FROM test me WHERE
+ ( ( ( id = ? ) OR ( id = ? ) OR ( id = ? ) OR ( id = ? ) OR ( id = ? ) ) )
+ : 1 3 5 7 9
+}}
+
+こんなSQLにされてた。
+↓(追記)
+hideさんからの情報で、
+
+{{code Perl,4,
+$it = $schema->resultset('User')->search({id => {'in' =>[1,2,3,4,5]}})
+}}
+
+とすれば、
+
+{{code SQL,4,
+SELECT me.id, me.name, me.passwd FROM user me WHERE ( id IN ( ?, ?, ?, ?, ? ) ): 1 2 3 4 5
+}}
+
+このようなSQLが実行されました。
+hideさんthanks!
+
+例えばnameがnekokakで'''ない'''データがほしいなぁと思ったとき、
+{{code Perl,4,
+my $it = $schema->resultset('User')->search({name => {'!=' , 'nekokak'}});
+}}
+
+例えばorder byでidのでかい順番にデータ取得したいなぁと思ったとき、
+{{code Perl,4,
+my $it = $schema->resultset('User')->search({},{order_by => 'id DESC'});
+}}
+ポイントは初めの引数は検索条件になるからorder_byは第二引数にすっこと。
+
+
+例えばgroup byでnameカラムの同一データを絞り込みたいなぁと思ったとき、
+{{code Perl,4,
+my $it = $schema->resultset('User')->search({},{group_by => 'name'});
+}}
+
+例えばnameにnekoが含まれ、idが10以上のデータがほしいなぁと思ったとき、
+{{code Perl,4,
+my $it = $schema->resultset('User')->search({id => {'>' => 10},name => {'like', '%neko%'}});
+}}
+
+(id = 1 and name = 'nekokak') or name = 'nomaneko'みたいなWhere句もOK
+
+{{code Perl,4,
+my $it = $schema->resultset('User')->search({
+ -or => [
+ -and => [id => 1,name=>'nekokak'],
+ name => 'nomaneko',
+ ],
+});
+}}
+
+こんな感じで複雑な検索条件も指定できまつ
+
+!!nextメソッド/allメソッド
+
+nextメソッドはイテレータ的使い方をする
+searchメソッドで複数レコード取ってきて、updateかます例。
+
+{{code Perl,4,
+my $it = $schema->resultset('User')->search();
+while ( my $user = $it->next ) {
+ $user->name('nomaneko2');
+ $user->update;
+}
+}}
+
+allメソッドの場合はこんなの
+
+{{code Perl,4,
+my $it = $schema->resultset('User')->search();
+for my $user ( $it->all ) {
+ $user->name('nomaneko2');
+ $user->update;
+}
+}}
+
+allメソッドの場合は検索結果の配列を返す。
+
+!!search_likeメソッド
+
+例えばnameにnekoが含まれるものがほしいなぁと思ったとき、
+{{code Perl,4,
+my $it = $schema->resultset('User')->search_like({name => '%neko%'});
+}}
+
+でも、基本的にsearchメソッドでもできるしsearch使えばいいっぽい。
+
+!!searchメソッドでページング
+
+10件ずつ表示みたいな、
+{{code Perl,4,
+my $it = $schema->resultset('User')->search({},{row => 10});
+my $p = $it->page(1);
+while ( my $user = $p->next ) {
+ print $user->id,':',$user->name,"\n";
+}
+}}
+$it->page(1);をせずに$itをnextメソッドでガリガリまわすと全て取れる罠。
+それが嫌な場合はページを指定するべし。
+{{code Perl,4,
+my $it = $schema->resultset('User')->search({},{page => 1,row => 10});
+}}
+2ページ目に進みたい時は
+{{code Perl,4,
+my $p = $it->page(2);
+}}
+とセットするだけ。
+
+!!insertメソッドで色々
+
+例えば、
+
+{{code Perl,4,
+my $l = $schema->resultset('User')->create({id => 25, name => "nomaneko"});
+}}
+こんな感じで、データをinsertした時、戻りを受け取っておくと、
+{{code Perl,4,
+print $l->last_insert_id,"\n";
+}}
+と、最後にinsertかましたプライマリキーの値をとれる。
+意地悪的に、こうする、
+{{code Perl,4,
+my $l = $schema->resultset('User')->create({id => 26, name => "nomaneko"});
+$schema->resultset('User')->create({id => 27, name => "nomaneko"});
+print $l->last_insert_id,"\n";
+}}
+するとちゃんと27が取れてくる。負けますた。
+
+コネクションを分けてみる、
+{{code Perl,4,
+my $schema = Neko::Schema->connect('dbi:mysql:nekodb','nekokak','******');
+my $schema2 = Neko::Schema->connect('dbi:mysql:nekodb','nekokak','******');
+my $l = $schema->resultset('User')->create({id => 28, name => "nomaneko"});
+$schema->resultset('User')->create({id => 29, name => "nomaneko"});
+$schema2->resultset('User')->create({id => 30, name => "nomaneko"});
+print $l->last_insert_id,"\n";
+}}
+当然29が取れますた。
+
+!!毎回のresultsetがうざい
+
+{{code Perl,4,
+my $u = $schema->resultset('User');
+}}
+
+こうすりゃ$u経由でsearchとかでける。
+
+!!countメソッドで
+
+単純にUserテーブルのカウントをとりたい場合、
+{{code Perl,4,
+my $n = $schema->resultset('User');
+my $count = $n->count({});
+print $count,"\n";
+}}
+これだけ。
+nameがnomanekoのユーザのカウントをとりたい場合、
+{{code Perl,4,
+my $count = $n->count({name => 'nomaneko'});
+}}
+そう、これだけ。
+nameでnomaが頭につくユーザのカウントをとりたい場合、
+{{code Perl,4,
+my $count = $n->count({name => {'like','noma%'}});
+}}
+ただ、これだけ。
+
+!!search_literalメソッドで
+
+自分でBind条件設定したい場合、
+{{code Perl,4,
+my $n = $schema->resultset('User');
+my $where = 'id = ? AND name = ?';
+my @bind = (9,'nekokak');
+my $it = $n->search_literal($where,@bind);
+while ( my $user = $it->next ) {
+ print $user->id,':',$user->name,"\n";
+}
+}}
+こんな感じでOK。でも、あんまり使わない希ガス。
+
+!!resetメソッドで
+
+イテレータで行をすすめててはじめに戻したい場合、
+{{code Perl,4,
+my $it = $n->search();
+my $i;
+while ( my $user = $it->next ) {
+ if ( $i == 2 ) {
+ $it->reset;
+ }
+ print $user->id,':',$user->name,"\n";
+ $i++;
+}
+}}
+ひそかに便利かも。
+
+!!find_or_createメソッドで
+
+アプリ作ってたら絶対にこの手のシチュエーション発生するよね、
+あればselectしてなければinsert
+{{code Perl,4,
+my $user = $n->find_or_create({id => 23,name=>"mogeneko"});
+print $user->id,':',$user->name,"\n";
+}}
+
+!!update_or_createメソッドで
+
+むしろこっちの方がfind_or_createよりも頻度高し
+{{code Perl,4,
+$n->update_or_create({id => 24,name=>"mogeneko1"});
+}}
+レコードが存在しなければinsertしてあればupdateしてくれるスグレモノ。
+
+!!1:多の関係を試す
+
+当然これができないと問題外。ちなみにDBIx::ClassのPODは分かりにくかったりする。
+試すテーブルは初めのuserテーブルとこのbookmarkテーブル。
+
+{{code SQL,4,
+create table bookmark (
+ id int(10) NOT NULL auto_increment,
+ user_id int(10) NOT NULL,
+ url text NOT NULL,
+ PRIMARY KEY (id),
+ INDEX (user_id),
+ FOREIGN KEY (user_id) REFERENCES user(id)
+) ENGINE = InnoDB;
+}}
+
+user:bookmark=1:nの関係でつ。
+
+!bookmarkテーブルにマッピングさせるモジュール
+
+Bookmarkテーブルは1userテーブルに属する為、belongs_toでリレーションを設定
+
+{{code Perl,4,
+package Neko::Schema::Bookmark;
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class';
+
+__PACKAGE__->load_components(qw/ PK::Auto::MySQL Core/);
+__PACKAGE__->table('bookmark');
+__PACKAGE__->add_columns(qw/id user_id url/);
+__PACKAGE__->set_primary_key('id');
+
+__PACKAGE__->belongs_to(user_id => 'Neko::Schema::User');
+
+1;
+}}
+
+!userテーブルにマッピングしてたモジュールにリレーションの追加
+
+userテーブルはbookmarkを多数もつ為、Neko::Schema::Userモジュールにhas_manyで設定
+
+{{code Perl,4,
+__PACKAGE__->has_many(bookmark => 'Neko::Schema::Bookmark', 'user_id');
+}}
+
+!スキーマの修正
+
+Bookmarkテーブルが追加されたから、Neko::Schemaのload_classesの部分を
+
+
+{{code Perl,4,
+__PACKAGE__->load_classes(qw/User Bookmark/);
+}}
+
+こうする。
+
+!Userからのselect
+
+Userからbookmarkを検索する場合、
+
+{{code Perl,4,
+my $schema = Neko::Schema->connect('dbi:mysql:nekodb','nekokak','******');
+
+my $userit = $schema->resultset('User')->search({name => 'nekokak'});
+while ( my $user = $userit->next ) {
+ my $bookmark = $user->bookmark;
+ while ( my $bkit = $bookmark->next ) {
+ print $bkit->id,':',$user->id,':',$bkit->url,"\n";
+ }
+}
+}}
+
+!Bookmarkからのselect
+
+BookmarkからUserを検索する場合、
+
+{{code Perl,4,
+my $bkit = $schema->resultset('Bookmark')->search();
+while ( my $bookmark = $bkit->next ) {
+ my $user = $bookmark->user_id;
+ print $user->id,':',$bookmark->id,':',$user->name,':',$bookmark->url,"\n";
+}
+}}
+
+Userからの検索とは異なりBookmarkには1つのUserしか存在しない為、
+$bookmark->user_id;
+とするだけで、該当のデータが取得される。
+
+!!こんな感じでinsertもOK
+
+{{code Perl,4,
+my $i = $schema->resultset('User')->create({name => 'nomaneko'});
+$schema->resultset('Bookmark')->create({
+ user_id => $i->last_insert_id ,
+ url => 'http://d.hatena.ne.jp/nomaneko/'}
+);
+}}
+
+!!inflate/deflateを試す
+
+loginテーブルを作ります。このテーブルはuserテーブルと1対1の関係です。
+
+{{code SQL,4,
+create table login (
+ id int(10) NOT NULL,
+ login_time DATETIME,
+ PRIMARY KEY (id),
+ FOREIGN KEY (id) REFERENCES user(id)
+) ENGINE = InnoDB;
+}}
+
+!loginテーブルにマッピングさせるモジュール
+
+might_haveメソッドでloginテーブルのidとuserテーブルのリレーションを構築
+inflate_columnメソッドでlogin_timeのinflateとdeflateを設定
+
+{{code Perl,4,
+package Neko::Schema::Login;
+
+use strict;
+use warnings;
+use base 'DBIx::Class';
+use DateTime::Format::MySQL;
+
+__PACKAGE__->load_components(qw/PK::Auto::MySQL Core/);
+__PACKAGE__->table('login');
+__PACKAGE__->add_columns(qw/id login_time/);
+__PACKAGE__->set_primary_key('id');
+
+__PACKAGE__->might_have(id => 'Neko::Schema::User');
+__PACKAGE__->inflate_column('login_time', {
+ inflate => sub { DateTime::Format::MySQL->parse_datetime(shift); },
+ deflate => sub { DateTime::Format::MySQL->format_datetime(shift); },
+});
+}}
+
+!userテーブルにマッピングしてたモジュールにリレーションの追加
+
+Neko::Schema::Userにmight_haveを追加します。
+
+{{code Perl,4,
+__PACKAGE__->might_have(id => 'Neko::Schema::Login');
+}}
+
+!スキーマの修正
+
+Neko::SchemaにLoginを追加
+
+{{code Perl,4,
+__PACKAGE__->load_classes(qw/User Bookmark Login/);
+}}
+
+!userテーブルとloginテーブルへのinsert
+
+userテーブルにデータをつっこんでついでにloginテーブルにもデータつっこみます。
+
+{{code Perl,4,
+my $i = $schema->resultset('User')->create({name => 'nekokak'});
+$schema->resultset('Login')->create({id => $i->last_insert_id,
+ login_time => '2006-02-03'});
+}}
+
+!loginテーブルのselect
+
+loginテーブルをselectしてそこからついでにuserのデータも引っぱってます。
+
+{{code Perl,4,
+my $it = $schema->resultset('Login')->search();
+while ( my $login = $it->next ) {
+ my $u = $login->user_id;
+ print $login->id,':',$u->name,':',$login->login_time,"\n";
+}
+}}
+
+inflate/deflateにはTime::Pieceとかも当然使えます。
+
+!!エラー発生ウワァァァァァァヽ(`Д´)ノァァァァァァン!な時
+
+{{code Perl,4,
+$schema->storage->debug(1);
+$schema->storage->debugfh(IO::File->new('/tmp/trace.out', 'w'));
+}}
+
+で/tmp/trace.outにログが出力されまつ。
+ログの内容はこんな感じ。
+
+{{code SQL,4,
+ SELECT me.id, me.login_time FROM login me WHERE ( naem = ? ): nomaneko
+}}
+
+!!SQLiteを使うときの注意
+
+{{word '''MySQLでも駄目だったのでプライマリのないテーブルの場合は要注意''',red,medium}}
+
+typesterさんがDBICのMLにDBD::SQLiteの制限に関するやり取りやってたので参考にすべし。
+
+たとえばこんな感じで、
+
+{{code Perl,4,
+my $schema = Neko::Schema->connect('dbi:SQLite:/home/nekokak/dbix/nekodb.db');
+
+my $n = $schema->resultset('User');
+my $it = $n->search();
+while ( my $user = $it->next ) {
+ print $user->id,':',$user->name,"\n";
+}
+}}
+
+問題なくデータ取れます。
+そこでupdateと絡めてやると、たとえばこんなの。
+
+{{code Perl,4,
+my $schema = Neko::Schema->connect('dbi:SQLite:/home/nekokak/dbix/nekodb.db');
+
+my $n = $schema->resultset('User');
+
+my $it = $n->search();
+while ( my $user = $it->next ) {
+ $user->name('mogeneko');
+ $user->update;
+}
+}}
+
+
+ DBD::SQLite::st execute failed: database table is locked(1) at dbdimp.c line 398 at /usr/lib/perl5/site_perl/5.8.6/DBIx/Class/Storage/DBI.pm line 305.
+ Use of uninitialized value in numeric eq (==) at /usr/lib/perl5/site_perl/5.8.6/DBIx/Class/Row.pm line 103.
+ DBIx::Class::Relationship::CascadeActions::update(): Can't update Neko::Schema::User=HASH(0x8d9f010): row not found at ./test.pl line 17
+
+こんな感じのエラーになった。
+
+なのでこうする、
+
+{{code Perl,4,
+my $schema = Neko::Schema->connect('dbi:SQLite:/home/nekokak/dbix/nekodb.db');
+
+my $n = $schema->resultset('User');
+
+my $it = $n->search();
+#while ( my $user = $it->next ) {
+foreach my $user ( $it->all ) {
+ $user->name('mogeneko');
+ $user->update;
+}
+}}
+
+
+すると、
+
+ DBIx::Class::Relationship::CascadeActions::update(): Can't update Neko::Schema::User=HASH(0x9b01cb0): updated more than one row at ./test.pl line 17
+
+なんじゃこのエラーは。と思ったらどうも、一発目のupdateで一気に全部アップデートかまされてる模様。
+
+レコードが
+
+,id,name
+,1,nekokak
+,2,nomaneko
+,3,mogeneko
+
+こんな感じであるとして、
+
+{{code Perl,4,
+my $n = $schema->resultset('User');
+my $it = $n->search({id => [1,2]});
+while ( my $user = $it->next ) {
+ print $user->id,':',$user->name,"\n";
+}
+}}
+
+これを実行すると、
+
+ $ ./test.pl
+ 1:nekokak
+ 2:nomaneko
+ $
+
+とちゃんと想定したデータが取れてきます。
+んが!!
+
+{{code Perl,4,
+my $n = $schema->resultset('User');
+my $it = $n->search({id => [1,2]});
+foreach my $user ( $it->all ) {
+ $user->name('hogeneko');
+ $user->update;
+}
+}}
+
+こんな感じでidが1,2のものだけhogenekoにupdateしようとしたら、、、
+
+{{code SQL,4,
+sqlite> select * from user;
+1|hogeneko
+2|hogeneko
+3|hogeneko
+sqlite>
+}}
+
+こんな感じにされてしまいますた。要注意!!
+
+!MLの回答を元に
+
+オイラの質問:
+http://lists.rawmode.org/pipermail/dbix-class/2006-February/000672.html
+
+回答:
+http://lists.rawmode.org/pipermail/dbix-class/2006-February/000681.html
+
+DBICのMLでも、プライマリの無いテーブルは良くないと指摘しつつ、
+DBICでは現状対応していないと言われました。
+
+プライマリキーの無いテーブルの場合は例えばこんな風に同一内容にはupdateは正常に実行される
+
+{{code Perl,4,
+$schema->resultset('Test')->search({id => [1,2,3],name =>'test'})->update({ name => 'test 1'});
+}}
+
+プライマリーの無いテーブルの場合、下の例は有効には動作せず、
+現状全カラム初回のupdateで更新されてしまう。
+
+{{code Perl,4,
+my $it = $t->search({id => [1,2,3],name => 'test'});
+my $i=1;
+for ($it->all) {
+ $_->name("test $i");
+ $_->update;
+ $i++;
+}
+}}
+
+あと、もう一つの回避策としては、
+
+こんなテーブル構成で、
+{{code SQL,4,
+CREATE TABLE test (
+ id INTEGER NOT NULL,
+ name TEXT NOT NULL,
+ foo TEXT
+);
+}}
+
+こんなデータの場合
+{{code SQL,4,
+ sqlite> select * from test;
+ 1|test|hoge
+ 1|sub_test|hoge
+ 2|sub_test|hoge
+ 2|test|hoge
+ 3|test|hoge
+ 3|sub_test|hoge
+ sqlite>
+}}
+
+testテーブルへのマッピングをこんな感じにidとnameでプライマリ指定します。
+
+{{code Perl,4,
+package Neko::Schema::Test;
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class';
+__PACKAGE__->load_components(qw/Core/);
+__PACKAGE__->table('test');
+__PACKAGE__->add_columns(qw/id name foo/);
+#__PACKAGE__->set_primary_key('id');
+__PACKAGE__->set_primary_key(qw/id name/);
+
+1;
+}}
+
+で、こんな感じのスクリプトを実行すると、
+
+{{code Perl,4,
+my $it = $schema->resultset('Test')->search({id => [1,2,3] , name => 'test'});
+my $i=0;
+
+for ($it->all) {
+ $_->foo("test $i");
+ $_->update;
+ $i++;
+}
+}}
+
+こんな感じでupdateされます。
+
+{{code SQL,4,
+sqlite> select * from test;
+1|test|test 0
+1|sub_test|hoge
+2|sub_test|hoge
+2|test|test 1
+3|test|test 2
+3|sub_test|hoge
+sqlite>
+}}
+
+でも、(いい例ではない&分かりにくいですが)
+
+{{code Perl,4,
+my $it = $schema->resultset('Test')->search({id => 1 , name => 'sub_test'});
+my $i=0;
+
+for ($it->all) {
+ $_->name("sub_test2");
+ $_->update;
+ $i++;
+}
+}}
+
+こんな感じでプライマリの一つであるnameを更新しようとすると、
+
+{{code SQL,4,
+ UPDATE test SET name = ? WHERE ( id = ? AND name = ? ): sub_test2 1 sub_test2
+}}
+
+こんなSQLが実行されてしまいます。これは微妙。。。
+
+! バージョン0.05003
+
+プライマリーの無いテーブルについては一部制限を設けられました。
+まあ、意図しないテーブルのupdateを回避できるのですが。
+プライマリーの無いテーブルに対し、こういう形でupdateをかけると、
+
+{{code Perl,4,
+my $it = $schema->resultset('Test')->search({id => [1,2,3] , name => 'sub test'});
+for ($it->all) {
+ $_->foo("fixed");
+ $_->update;
+}
+}}
+
+こういうエラーがでます。
+
+ DBIx::Class::Relationship::CascadeActions::update(): Cannot safely update a row in a PK-less table at ./test.pl line 49
+
+そして、全カラムupdateは防がれるようになりました。
+プライマリの無いテーブルってのも確かにおかしな話なのですが、ありえなくはないので、
+そういうテーブルをupdateする時は、search()->update();でやりましょう。
+
+!!!DBIx::Class::Schema::Loaderを使ってみる
+
+!!PODをほぼそのまま実験してみた
+
+DBIx::Class::Schema::Loaderを継承して、DBの設定をする。
+
+{{code Perl,4,
+package Neko::SchemaLoader;
+
+use strict;
+use warnings;
+use base 'DBIx::Class::Schema::Loader';
+
+__PACKAGE__->load_from_connection(
+ dsn => "dbi:mysql:nekodb",
+ user => "nekokak",
+ password => "******",
+ relationships => 1,
+ options => { AutoCommit => 1 },
+ debug => 1,
+);
+
+1;
+}}
+
+どんな感じになるのかダンプしてみた。
+
+{{code Perl,4,
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+use Neko::SchemaLoader;
+use Data::Dumper;
+
+my $schema = "Neko::SchemaLoader";
+
+my @tables = $schema->loader->tables;
+print Dumper(\@tables);
+}}
+
+そしたらこんなんでますた
+
+ ### START DBIx::Class::Schema::Loader dump ###
+ # Initializing table "login" as "Neko::SchemaLoader::Login"
+ Neko::SchemaLoader::Login->table('login');
+ Neko::SchemaLoader::Login->add_columns('id', 'login_time')
+ Neko::SchemaLoader::Login->set_primary_key('id')
+ # Initializing table "user" as "Neko::SchemaLoader::User"
+ Neko::SchemaLoader::User->table('user');
+ Neko::SchemaLoader::User->add_columns('id', 'name')
+ Neko::SchemaLoader::User->set_primary_key('id')
+ # Belongs_to relationship
+ Neko::SchemaLoader::Login->belongs_to( 'id' => 'Neko::SchemaLoader::User',{ id => id });
+
+ # Has_many relationship
+ Neko::SchemaLoader::User->has_many( 'logins' => 'Neko::SchemaLoader::Login',{ id => id });
+
+ );
+
+ ### END DBIx::Class::Schema::Loader dump ###
+ $VAR1 = [
+ 'login',
+ 'user'
+ ];
+
+スバラシス。
+ただ、リレーションの部分がこちらの想定している形でないので、
+DBの設定のrelationshipsをやめてみるとこんなんになった。
+
+ ### START DBIx::Class::Schema::Loader dump ###
+ # Initializing table "login" as "Neko::SchemaLoader::Login"
+ Neko::SchemaLoader::Login->table('login');
+ Neko::SchemaLoader::Login->add_columns('id', 'login_time')
+ Neko::SchemaLoader::Login->set_primary_key('id')
+ # Initializing table "user" as "Neko::SchemaLoader::User"
+ Neko::SchemaLoader::User->table('user');
+ Neko::SchemaLoader::User->add_columns('id', 'name')
+ Neko::SchemaLoader::User->set_primary_key('id')
+ ### END DBIx::Class::Schema::Loader dump ###
+ $VAR1 = [
+ 'login',
+ 'user'
+ ];
+
+これはDB設計の問題かなぁ。
+リレーションの追加は後で考えよう。
+
+どのテーブルがどんな名前のモジュールにされているのかを引っぱりたい場合は、
+
+{{code Perl,4,
+my $monikers = $schema->loader->monikers;
+print Dumper($monikers);
+}}
+
+ $VAR1 = {
+ 'user' => 'User',
+ 'login' => 'Login'
+ };
+
+モジュールのフルネームが知りたい場合は、
+
+{{code Perl,4,
+my $classes = $schema->loader->classes;
+print Dumper($classes);
+}}
+
+ $VAR1 = {
+ 'user' => 'Neko::SchemaLoader::User',
+ 'login' => 'Neko::SchemaLoader::Login'
+ };
+
+Userテーブルにselectかます
+
+{{code Perl,4,
+my $it = $schema->resultset($monikers->{'user'})->search;
+while ( my $user = $it->next ) {
+ print $user->id,':',$user->name,"\n";
+}
+}}
+
+細かい設定をなんとかできたら激しく便利ですな!
+で、とりあえずこんな感じでリレーション設定できる。
+{{code Perl,4,
+$classes->{'user'}->might_have(login_id => $classes->{'login'});
+my $it = $schema->resultset($monikers->{'user'})->search({id => 1});
+while ( my $user = $it->next ) {
+ my $login = $user->login_id;
+ print $user->id,':',$login->login_time,':',$user->name,"\n";
+}
+}}
+
+!!!課題
+
+*might_haveとhas_oneの違いがよーわからんので調べる。
+*many_to_manyを試す。
+*DBIx::Class::Validationを見る。
+*DBIx::Class::Loaderを試す。
+*むしろDBIx::Class::Schema::Loaderか?
+
+!!!参考
+ほとんどhttp://search.cpan.org/~mstrout/DBIx-Class/lib/DBIx/Class/Manual/SchemaIntro.podからのパクリw
+
+!!!とりあえず作ったモジュール
+
+::DigestColumns::{{ref DBIx-Class-DigestColumns-0.01.tar.gz }}
+
+とりあえず作ったから残しておく。↓
+::MD5Columns(必要無し)::{{ref DBIx-Class-MD5Columns-0.01.tar.gz }}
+::EscapeSearch(必要無し)::{{ref DBIx-Class-EscapeSearch-0.01.tar.gz }}
+
+{{category Perl,nolink}}