多対多のサンプルとしてTags: Database schemasの“Toxi” solutionをDBICで書いてみる。
関連を表すテーブルに対しては、1対多の関係を設定しておいて、更にmany_to_manyを追加する
図にしてみたらわかりやすくなった。
ちなみに、1対多はこちらを、多対多はこちらを参考にしました。
Kzfm::Schema
use 5.008008; use strict; use warnings; use base 'DBIx::Class::Schema'; our $VERSION = '0.01'; __PACKAGE__->load_classes(qw/Tag Bookmark TagMap/); 1;
Kzfm::Schema::Tag
use strict; use warnings; use base 'Kzfm::Schema'; __PACKAGE__->load_components(qw/PK::Auto::SQLite Core/); __PACKAGE__->table('tag'); __PACKAGE__->add_columns(qw/id name/); __PACKAGE__->set_primary_key('id'); __PACKAGE__->has_many(tagmap => 'Kzfm::Schema::TagMap','tag_id'); __PACKAGE__->many_to_many('bookmarks' => 'tagmap','bookmark_id'); 1;
Kzfm::Schema::Bookmark
use strict; use warnings; use base 'Kzfm::Schema'; __PACKAGE__->load_components(qw/PK::Auto::SQLite Core/); __PACKAGE__->table('bookmark'); __PACKAGE__->add_columns(qw/id name uri description time_created/); __PACKAGE__->set_primary_key('id'); __PACKAGE__->has_many(tagmap => 'Kzfm::Schema::TagMap','bookmark_id'); __PACKAGE__->many_to_many('tags' => 'tagmap','tag_id'); 1;
Kzfm::Schema::TagMap
use strict; use warnings; use base 'Kzfm::Schema'; __PACKAGE__->load_components(qw/PK::Auto::SQLite Core/); __PACKAGE__->table('tagmap'); __PACKAGE__->add_columns(qw/id bookmark_id tag_id/); __PACKAGE__->set_primary_key('id'); __PACKAGE__->belongs_to('bookmark_id' => 'Kzfm::Schema::Bookmark'); __PACKAGE__->belongs_to('tag_id' => 'Kzfm::Schema::Tag'); 1;
制約の部分だけ、考えてみる。
__PACKAGE__->belongs_to('カラム名(アクセサ?)' => 'スキーマ(pm)'); __PACKAGE__->has_many(テーブル名 => 'スキーマ(pm)','カラム名(アクセサ?)'); __PACKAGE__->many_to_many('任意のキー名' => 'テーブル名','多対多関係のカラム');
- belongs_toはまぁわかりやすい。
- many_to_manyは任意にキー名決められるのにhas_manyはキー値にテーブル名指定しないとエラー吐くのが謎。
- many_to_manyでテーブル名のとこをKzfm::Schema::TagMapってやるのが駄目な理由がよくわからない。
あと、さらにユーザーを追加する場合に、ユーザーとブックマークも多対多の関係になるけど、こっちも正規化したほうがいいのか、むしろやりすぎないほうがむしろいいのか悩む。