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にトレースログが出力されます。
ログレベルなどについては下記を見て下さい。
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;
普通、必要ないような^^;