Perl/DBIC

Top Diff List Search RSS Login
Page :: Perl / DBIC

VERSION-0.05000での記述。http://search.cpan.org/~mstrout/DBIx-Class/
ドキュメントも当初に比べれば増えてきたし、そっち見たほうがよかばい。
まあ以下は簡単なまとめで。一通り使えるくらいは書きたい。
このサイトはWikiなので途中途中に色々追加したり修正したりしますからご注意を

DBIx::Class::Schemaを使ってみる

これからDBICではSchemaメインらしい。

使うテーブル作成SQL

1
2
3
4
5
create table user (
    id     int(10) NOT NULL auto_increment,
    name   varchar(256) NOT NULL,
    PRIMARY KEY (id)
) ENGINE = InnoDB;

アプリで使うDBスキーマの定義

下の例ではUserテーブルをこのアプリケーションで使うよって感じかね。

1
2
3
4
5
6
7
8
9
package Neko::Schema;

use strict;
use warnings;
use base 'DBIx::Class::Schema';

__PACKAGE__->load_classes(qw/User/);

1;

load_classesにテーブル指定しないと、Neko::Schema::*が指定されたとみなす。

1
__PACKAGE__->load_classes();

複数に分かれたスキーマを扱いたい場合はこんな感じ。

1
2
3
4
5
6
__PACKAGE__->load_classes(
    {
        'Neko::Schema'      => qw/ User /,
        'Neko::OtherSchema' => qw/ Item /
    }
);

テーブルにマッピングさせるモジュールの定義

1
2
3
4
5
6
7
8
9
10
11
12
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#! /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メソッドで
検索条件を指定してみる。

1
2
3
4
5
6
7
8
9
10
11
12
13
#! /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と同じだけど、返りをスカラーで受け取るとイテレータに、配列で受け取ると
配列にしたデータを返してくれる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#! /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";
}

でも、これは必要ないデータまでとってきてくれたりするので、イテレータ使うべし。

コネクションを分ける

複数のコネクションが必要なら、

1
2
my $schema = Neko::Schema->connect('dbi:mysql:nekodb','nekokak','******');
my $schema2 = Neko::Schema->connect('dbi:mysql:nekodb','nekokak','******');

と、するだけぽい。

searchメソッドで色々

例えばidが5以上のデータをとりたいな〜って思った時なんか、

1
my $it = $schema->resultset('User')->search({id => { '>' => 5}});

例えばidが5以上でnameがnomanekoのデータがほしいなぁと思ったとき、

1
my $it = $schema->resultset('User')->search({id => { '>' => 5},name => 'nomaneko'});

例えばidが1,3,5,7,9のデータがほしいなぁと思ったとき、

1
my $it = $schema->resultset('User')->search({id => [1,3,5,7,9]});

これ、ちゃんとid in (1,3,5,7,9)にしてくれるっぽい。
してくれないみたい。。

1
2
3
 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さんからの情報で、

1
$it = $schema->resultset('User')->search({id => {'in' =>[1,2,3,4,5]}})

とすれば、

1
SELECT me.id, me.name, me.passwd FROM user me WHERE ( id IN ( ?, ?, ?, ?, ? ) ): 1 2 3 4 5

このようなSQLが実行されました。
hideさんthanks!

例えばnameがnekokakでないデータがほしいなぁと思ったとき、

1
my $it = $schema->resultset('User')->search({name => {'!=' , 'nekokak'}});

例えばorder byでidのでかい順番にデータ取得したいなぁと思ったとき、

1
my $it = $schema->resultset('User')->search({},{order_by => 'id DESC'});

ポイントは初めの引数は検索条件になるからorder_byは第二引数にすっこと。

例えばgroup byでnameカラムの同一データを絞り込みたいなぁと思ったとき、

1
my $it = $schema->resultset('User')->search({},{group_by => 'name'});

例えばnameにnekoが含まれ、idが10以上のデータがほしいなぁと思ったとき、

1
my $it = $schema->resultset('User')->search({id => {'>' => 10},name => {'like', '%neko%'}});

(id = 1 and name = 'nekokak') or name = 'nomaneko'みたいなWhere句もOK

1
2
3
4
5
6
my $it = $schema->resultset('User')->search({
    -or => [
        -and => [id => 1,name=>'nekokak'],
        name => 'nomaneko',
    ],
});

こんな感じで複雑な検索条件も指定できまつ

nextメソッド/allメソッド

nextメソッドはイテレータ的使い方をする
searchメソッドで複数レコード取ってきて、updateかます例。

1
2
3
4
5
my $it = $schema->resultset('User')->search();
while ( my $user = $it->next ) {
    $user->name('nomaneko2');
    $user->update;
}

allメソッドの場合はこんなの

1
2
3
4
5
my $it = $schema->resultset('User')->search();
for my $user ( $it->all ) {
    $user->name('nomaneko2');
    $user->update;
}

allメソッドの場合は検索結果の配列を返す。

search_likeメソッド

例えばnameにnekoが含まれるものがほしいなぁと思ったとき、

1
my $it = $schema->resultset('User')->search_like({name => '%neko%'});

でも、基本的にsearchメソッドでもできるしsearch使えばいいっぽい。

searchメソッドでページング

10件ずつ表示みたいな、

1
2
3
4
5
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メソッドでガリガリまわすと全て取れる罠。
それが嫌な場合はページを指定するべし。

1
my $it = $schema->resultset('User')->search({},{page => 1,row => 10});

2ページ目に進みたい時は

1
my $p = $it->page(2);

とセットするだけ。

insertメソッドで色々

例えば、

1
my $l = $schema->resultset('User')->create({id => 25, name => "nomaneko"});

こんな感じで、データをinsertした時、戻りを受け取っておくと、

1
print $l->last_insert_id,"\n";

と、最後にinsertかましたプライマリキーの値をとれる。
意地悪的に、こうする、

1
2
3
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が取れてくる。負けますた。

コネクションを分けてみる、

1
2
3
4
5
6
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がうざい

1
my $u = $schema->resultset('User');

こうすりゃ$u経由でsearchとかでける。

countメソッドで

単純にUserテーブルのカウントをとりたい場合、

1
2
3
my $n = $schema->resultset('User');
my $count = $n->count({});
print $count,"\n";

これだけ。
nameがnomanekoのユーザのカウントをとりたい場合、

1
my $count = $n->count({name => 'nomaneko'});

そう、これだけ。
nameでnomaが頭につくユーザのカウントをとりたい場合、

1
my $count = $n->count({name => {'like','noma%'}});

ただ、これだけ。

search_literalメソッドで

自分でBind条件設定したい場合、

1
2
3
4
5
6
7
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メソッドで

イテレータで行をすすめててはじめに戻したい場合、

1
2
3
4
5
6
7
8
9
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

1
2
my $user = $n->find_or_create({id => 23,name=>"mogeneko"});
print $user->id,':',$user->name,"\n";

update_or_createメソッドで

むしろこっちの方がfind_or_createよりも頻度高し

1
$n->update_or_create({id => 24,name=>"mogeneko1"});

レコードが存在しなければinsertしてあればupdateしてくれるスグレモノ。

1:多の関係を試す

当然これができないと問題外。ちなみにDBIx::ClassのPODは分かりにくかったりする。
試すテーブルは初めのuserテーブルとこのbookmarkテーブル。

1
2
3
4
5
6
7
8
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でリレーションを設定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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で設定

1
__PACKAGE__->has_many(bookmark => 'Neko::Schema::Bookmark', 'user_id');

スキーマの修正

Bookmarkテーブルが追加されたから、Neko::Schemaのload_classesの部分を

1
__PACKAGE__->load_classes(qw/User Bookmark/);

こうする。

Userからのselect

Userからbookmarkを検索する場合、

1
2
3
4
5
6
7
8
9
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を検索する場合、

1
2
3
4
5
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

1
2
3
4
5
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の関係です。

1
2
3
4
5
6
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を設定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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を追加します。

1
__PACKAGE__->might_have(id => 'Neko::Schema::Login');

スキーマの修正

Neko::SchemaにLoginを追加

1
__PACKAGE__->load_classes(qw/User Bookmark Login/);

userテーブルとloginテーブルへのinsert

userテーブルにデータをつっこんでついでにloginテーブルにもデータつっこみます。

1
2
3
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のデータも引っぱってます。

1
2
3
4
5
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とかも当然使えます。

エラー発生ウワァァァァァァヽ(`Д´)ノァァァァァァン!な時

1
2
$schema->storage->debug(1);
$schema->storage->debugfh(IO::File->new('/tmp/trace.out', 'w'));

で/tmp/trace.outにログが出力されまつ。
ログの内容はこんな感じ。

1
 SELECT me.id, me.login_time FROM login me WHERE ( naem = ? ): nomaneko

SQLiteを使うときの注意

MySQLでも駄目だったのでプライマリのないテーブルの場合は要注意

typesterさんがDBICのMLにDBD::SQLiteの制限に関するやり取りやってたので参考にすべし。

たとえばこんな感じで、

1
2
3
4
5
6
7
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と絡めてやると、たとえばこんなの。

1
2
3
4
5
6
7
8
9
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

こんな感じのエラーになった。

なのでこうする、

1
2
3
4
5
6
7
8
9
10
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で一気に全部アップデートかまされてる模様。

レコードが

idname
1nekokak
2nomaneko
3mogeneko

こんな感じであるとして、

1
2
3
4
5
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
$

とちゃんと想定したデータが取れてきます。
んが!!

1
2
3
4
5
6
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しようとしたら、、、

1
2
3
4
5
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は正常に実行される

1
$schema->resultset('Test')->search({id => [1,2,3],name =>'test'})->update({ name => 'test 1'});

プライマリーの無いテーブルの場合、下の例は有効には動作せず、
現状全カラム初回のupdateで更新されてしまう。

1
2
3
4
5
6
7
my $it = $t->search({id => [1,2,3],name => 'test'});
my $i=1;
for ($it->all) {
    $_->name("test $i");
    $_->update;
    $i++;
}

あと、もう一つの回避策としては、

こんなテーブル構成で、

1
2
3
4
5
CREATE TABLE test (
    id INTEGER NOT NULL,
    name TEXT NOT NULL,
    foo TEXT
);

こんなデータの場合

1
2
3
4
5
6
7
8
 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でプライマリ指定します。

1
2
3
4
5
6
7
8
9
10
11
12
13
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;

で、こんな感じのスクリプトを実行すると、

1
2
3
4
5
6
7
8
my $it = $schema->resultset('Test')->search({id => [1,2,3] , name => 'test'});
my $i=0;

for ($it->all) {
    $_->foo("test $i");
    $_->update;
    $i++;
}

こんな感じでupdateされます。

1
2
3
4
5
6
7
8
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>

でも、(いい例ではない&分かりにくいですが)

1
2
3
4
5
6
7
8
my $it = $schema->resultset('Test')->search({id => 1 , name => 'sub_test'});
my $i=0;

for ($it->all) {
    $_->name("sub_test2");
    $_->update;
    $i++;
}

こんな感じでプライマリの一つであるnameを更新しようとすると、

1
 UPDATE test SET name = ? WHERE ( id = ? AND name = ? ): sub_test2 1 sub_test2

こんなSQLが実行されてしまいます。これは微妙。。。

バージョン0.05003

プライマリーの無いテーブルについては一部制限を設けられました。
まあ、意図しないテーブルのupdateを回避できるのですが。
プライマリーの無いテーブルに対し、こういう形でupdateをかけると、

1
2
3
4
5
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の設定をする。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;

どんな感じになるのかダンプしてみた。

1
2
3
4
5
6
7
8
9
10
11
#! /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設計の問題かなぁ。
リレーションの追加は後で考えよう。

どのテーブルがどんな名前のモジュールにされているのかを引っぱりたい場合は、

1
2
my $monikers = $schema->loader->monikers;
print Dumper($monikers);
$VAR1 = {
          'user' => 'User',
          'login' => 'Login'
        };

モジュールのフルネームが知りたい場合は、

1
2
my $classes = $schema->loader->classes;
print Dumper($classes);
$VAR1 = {
          'user' => 'Neko::SchemaLoader::User',
          'login' => 'Neko::SchemaLoader::Login'
        };

Userテーブルにselectかます

1
2
3
4
my $it = $schema->resultset($monikers->{'user'})->search;
while ( my $user = $it->next ) {
    print $user->id,':',$user->name,"\n";
}

細かい設定をなんとかできたら激しく便利ですな!
で、とりあえずこんな感じでリレーション設定できる。

1
2
3
4
5
6
$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::DBIx-Class-DigestColumns-0.01.tar.gz(241)

とりあえず作ったから残しておく。↓

MD5Columns(必要無し)::DBIx-Class-MD5Columns-0.01.tar.gz(184)
EscapeSearch(必要無し)::DBIx-Class-EscapeSearch-0.01.tar.gz(216)


Last update time:2006/11/07 08:48:06