Class::DBIで3テーブル検索(katoさん編)

katoさんに教えていただいた方法で実装します。

変更のあったモジュールのみの抜粋で、残りはClass::DBIで3テーブル検索(実行編)
と同じです。

./Neko/OrderCust.pm

Neko::OrderCust->has_many(items => 'Neko::OrderItem');
がミソです。itemsという名前でNeko::OrderItemへリレーションを築いてます。


package Neko::OrderCust;
use strict;
use warnings;
use base 'Neko::DBI';
__PACKAGE__->table('order_cust');
__PACKAGE__->columns( Primary => qw[ no ]);
__PACKAGE__->columns( Essential => qw[ name ] );
Neko::OrderCust->has_many(items => 'Neko::OrderItem');
1;

./Neko/OrderItem.pm

Primary指定はno_subだけです。no_subにPrimary指定しないと期待した結果になりません。
noはEssential指定に変更しました。


package Neko::OrderItem;
use strict;
use warnings;
use base 'Neko::DBI';
__PACKAGE__->table('order_item');
__PACKAGE__->columns( Primary => qw[ no_sub ]);
__PACKAGE__->columns( Essential => qw[ no item_no ] );
Neko::OrderItem->has_a( item_no => 'Neko::Item' );
Neko::OrderItem->has_a( no => 'Neko::OrderCust' );
1;

実行スクリプトは以下です。


#! /usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Neko::OrderCust;
$\ = "\n";
my $order = Neko::OrderCust->retrieve(1);
print Dumper($order);
print $order->no;
print $order->name;
for my $item ($order->items) {
print $item->no;
print $item->no_sub;
print $item->item_no;
print $item->item_no->item_no;
print $item->item_no->item_name;
}

これでOrderCust経由での検索ができました。

実行結果はこんなのです。


$VAR1 = bless( {
'name' => 'nekokak',
'no' => '1'
}, 'Neko::OrderCust' );
1
nekokak
1
1
100
100
Tea
1
2
101
101
Candy


う〜んすばらしか。

しかし、実テーブルとのリレーションと同期がとれないのはしかたないのかなぁ。
まあ、実テーブルの設計がいけてないのがいけないのかもしれませんが、
実際に運用されているいけてない設計のDBと付き合うのは厳しいかもしれませんね。


(追記)

itemsで取得するデータをさらに絞り込むことが可能。
例えば以下のようにします。


#! /usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Neko::OrderCust;
$\ = "\n";
my $order = Neko::OrderCust->retrieve(1);
print Dumper($order);
print $order->no;
print $order->name;
for my $item ($order->items(no_sub => 2)) {
print $item->no;
print $item->no_sub;
print $item->item_no;
print $item->item_no->item_no;
print $item->item_no->item_name;
}

$order->items(no_sub => 2)
とすると、no_subの部分でさらに絞込みをかけた検索ができます。


(さらに追記)

Neko::OrderItemは
__PACKAGE__->columns( Primary => qw[ no no_sub ]);
と2つ、Primary指定してもOKでした。

しかしClass::DBIのキャッシュ結構面倒かもしれませんね。

$Class::DBI::Weaken_Is_Available

でキャッシュの操作できるっぽいです。

Class::DBIでもDBIをトレース

Class::DBIでもどんな風にSQLが実行されるかなどを見るには、

DBI->trace

を使います。
例えばこんなの


#! /usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Neko::OrderCust;
$\ = "\n";
DBI->trace(5 => "./logfile");
my $order = Neko::OrderCust->retrieve(1);
print Dumper($order);
print $order->no;
print $order->name;
for my $item ($order->items) {
print $item->no;
print $item->no_sub;
print $item->item_no;
print $item->item_no->item_no;
print $item->item_no->item_name;
}

こうするとlogfileにトレースログが出力されます。
ログレベルなどについては下記を見て下さい。

http://search.cpan.org/~timb/DBI/DBI.pm#TRACING

Class::DBI::Plugin::Clone

なんとなく作ってみました。

Class::DBIで作ったオブジェクトのクローンが欲しいときにでもどうぞ。


package Class::DBI::Plugin::Clone;
use strict;
use warnings;
use Carp;
use Clone qw(clone);
use vars '$VERSION';
$VERSION = '0.01';
sub import {
my $class = shift;
my $pkg = caller(0);
unless($pkg->isa('Class::DBI')){
croak(__PACKAGE__." is for Class::DBI application.");
}
no strict 'refs';
*{"$pkg\::clone"} = sub {
my ($class,$target) = @_;
clone($target);
};
}
1;

普通、必要ないような^^;