many-to-manyを殴り書き

今のところ、あまり必要に迫られているわけではないのですが、
覚書程度にDBICのmany-to-manyを試してみます。

Memberテーブル:Addressテーブル = n : m
みたいなな感じで。


package Proj::Schema::Member;
use strict;
use warnings;
use base 'Proj::Schema';

__PACKAGE__->table('member');
__PACKAGE__->add_columns(qw/
id
rid
name
created_on
timestamp
/);
__PACKAGE__->set_primary_key(qw/id/);
__PACKAGE__->has_many('member_address' => 'Proj::Schema::MemberAddress','member');
__PACKAGE__->many_to_many('addresses' => 'member_address','address');

1;

package Proj::Schema::Address;
use strict;
use warnings;
use base 'Proj::Schema';

__PACKAGE__->table('address');
__PACKAGE__->add_columns(qw/
id
rid
city
created_on
timestamp
/);
__PACKAGE__->set_primary_key(qw/id/);
__PACKAGE__->has_many('member_address' => 'Proj::Schema::MemberAddress','address');
__PACKAGE__->many_to_many('members' => 'member_address','member');

1;

MemberテーブルとAddressテーブルの間を取り持つテーブルを作成


package Proj::Schema::MemberAddress;
use strict;
use warnings;
use base 'Proj::Schema';

__PACKAGE__->table('member_address');
__PACKAGE__->add_columns(qw/
member
address
created_on
timestamp
/);
__PACKAGE__->set_primary_key(qw/member address/);
__PACKAGE__->belongs_to('member'=>'Proj::Schema::Member');
__PACKAGE__->belongs_to('address'=>'Proj::Schema::Address');

1;

こんな感じ。

Proj::Schema::Memberはhas_manyでProj::Schema::MemberAddressをもち
Proj::Schema::Addressもhas_manyでProj::Schema::MemberAddressを持ちます。
Proj::Schema::MemberAddressはそれぞれMemberとAddressに対してbelongs_toになると。

ここまでは特に変化球はないかと思うのですが、(たぶん)
Proj::Schema::MemberAddressではset_primary_keyで複数キーをプライマリ指定してます。

こっからめんどい。
many-to-many用の設定で、

Proj::Schema::Memberでは


__PACKAGE__->many_to_many('addresses' => 'member_address','address');

こんな設定をします。
addressesってのがmany-to-manyのキーみたいなのん。(アクセサになる)
member_addressってのがhas_manyしている設定のキー。
addressってのがMemberAddress(中間テーブル)からAddressテーブルにさかのぼる
キーで、設定したbelongs_toのキー。

Proj::Schema::Addressでは


__PACKAGE__->many_to_many('members' => 'member_address','member');

こんな設定。

membersがmany-to-manyのキー。
member_addressがhas_manyしている設定のキー。
memberってのがMemberAddress(中間テーブル)からMemberテーブルにさかのぼる
キーになる、設定したbelongs_toのキー。

こんな感じです。


実験スクリプト


## データの初期化(とりあえず全部消す)
$self->model('Member')->search({})->delete_all;
$self->model('Address')->search({})->delete_all;
$self->model('MemberAddress')->search({})->delete_all;

## Memberテーブル作成
my $member1 = $self->model('Member')->create({name => 'タロウ'});
my $member2 = $self->model('Member')->create({name => 'ジロウ'});

## Addressテーブル作成
my $address1 = $self->model('Address')->create({city => 'Tokyo'});
my $address2 = $self->model('Address')->create({city => 'Kyoto'});
my $address3 = $self->model('Address')->create({city => 'Osaka'});

## MemberテーブルとAddressテーブルを関連付けするMemberAddressにデータ作成
## タロウ:Tokyo
## タロウ:Kyoto
## ジロウ:Tokyo
## ジロウ:Osaka
## こんな感じの設定
my $member_address1 = $self->model('MemberAddress')->create({member => $member1->id, address => $address1->id});
my $member_address2 = $self->model('MemberAddress')->create({member => $member1->id, address => $address2->id});
my $member_address3 = $self->model('MemberAddress')->create({member => $member2->id, address => $address1->id});
my $member_address4 = $self->model('MemberAddress')->create({member => $member2->id, address => $address3->id});

## R実行
## Memberテーブルから全レコード取得
my $member_rs = $self->model('Member')->search({});
while (my $member = $member_rs->next) {
## XXX:many-to-many発動
## addressesはmany_to_manyで設定したキー(アクセサ)
my $address_rs = $member->addresses;
while (my $address = $address_rs->next) {
warn $member->name,':',$address->city;
}
}

こんな感じです。
説明適当ですが、分かるでしょう^^;
(うそは書いて無いとおもう。。)