はじめに
Railsにおけるアソシエーション(belongs_to
,has_many
,has_one
)について、それから主キーの設定について分かったようで分かっていない部分があったので、自分の理解のためにも簡単な具体例を作ってみた。
取り上げる相関
今回使用する相関図はコチラ
大抵、商品の管理システムや従業員データなど例が取り上げられるので、イメージしやすそうな某冒険友情活劇を例にうまいこと当てはめてみた。(逆に分かりづらくなっているかも)
どれを主キーにするか問題
意外と悩んだのがどれを主キーにしたらよいのかという部分。
そもそも主キーとはなんのために設定するのかというところから考えてみる。
主キーに適するのは
- テーブル内でレコードを一意に識別することができるように指定される項目
- 主キーに選ばれた列はすべてのレコードが異なる値を持たなければならず、NULL値とすることもできない
主キーの選択
主キーの定義には次のように書かれている。
候補キーが複数あるとき、組を識別するという機能においてそれらの間に差異はないため、主キーにどれを選んでも論理的には問題がない。
しかし実用性を考えると以下に注意して選択するとよい。
- 主キーは検索のキーとして利用されたり、他の関係に参照のために格納されたりする確率が高いため、できる限りデータ量の小さい方がよい
- 他の関係で主キーを使用していた場合、主キーを更新すると他の関係の値(外部キー)も同時に更新しなければならなくなるため、更新がかからない項目がよい
主キーを用いた例
生徒名簿(生徒番号, 生徒名, クラス)という関係
生徒番号が主キーになり得る。
同姓同名を考慮すると、生徒番号は唯一の候補キーであるから、代理キーはない。
町村(町村ID, 町村名, 郡名, 都道府県名)という関係
町村ID と {都道府県名, 郡名, 町村名} が候補キーであり、いずれかが主キーになり得る。
例えば、町村ID を主キーにした場合、{都道府県名, 郡名, 町村名} は代理キーとなる。
以上のことを踏まえて選択
- キャラクターは中身の情報更新が多そうな気もする、データ量も多い
- インデックスとして機能するものがよい
という観点から「海賊団」を主キーに選択。
「麦わらの一味」と検索をかけたら、ズラーーっと船員が表示されると便利だと思うので。
なお、所属がないキャラクターは「無所属」とする。(NULL回避)
データベース
あまりこの漫画について知らないのですが、それっぽいのを設定した。
[海賊団(team)]
id (主キー) | team_name | ship |
---|---|---|
1 | 無所属 | なし |
2 | 麦わらの一味 | サウザンド・サニー号 |
3 | バギー海賊団 | ビックトップ号 |
4 | アーロン一味 | シャーク・サバーブ号 |
[キャラクター(ch)]
※prize_money=懸賞金 (金額はテキトー)
id | team_id(外部キー) | ch_name | prize_money |
---|---|---|---|
1 | 2 | ルフィ | 2億 |
2 | 2 | ナミ | 100万 |
3 | 3 | バギー | 3億 |
4 | 2 | チョッパー | 1万 |
[悪魔の実(skill)]
id | ch_id(外部キー) | skill_name | genre |
---|---|---|---|
1 | 1 | ゴムゴム | 超人(パラミシア) |
2 | 23 | モクモク | 自然(ロギア) |
3 | 3 | バラバラ | 超人(パラミシア) |
4 | 4 | ヒトヒト | 動物(ゾオン) |
キャラクターに関しては、身長、体重、性別、出身などなど色々情報を入れられそうですね。
また、外部キーをどこに作るか問題もあったのでそれについては後述します。
(悪魔の実のテーブルにch_idを作るか、キャラクターのテーブルにskill_idを作るかみたいな問題)
アソシエーション
相関図をもう一度載せます。
海賊団とキャラクターの関係は分かり易いと思います。
海賊団は複数のメンバーが所属し、キャラクターはそこに所属している。
いわゆる「多:1」の関係です。
問題はキャラクターと悪魔の実の能力の関係です。
has_oneとbelongs_toの使い分け
この関係は「1:1」です。
たしか複数の実の能力を持つことができないみたいな設定でしたよね?
(黒ひげは能力2つもってる的なことを聞いたような、、ややこしいので無視!笑)
ところで、どちらをhas_one
にするの?と引っかかったのでまとめます。
has_oneとbelongs_toの条件
まず、「主従関係」を考えてみると良い。
主となる方が has_one
で従となる方が belongs_to
になる。
今回の例では悪魔の実の能力を持たないキャラクターは存在するが、悪魔の実自体は必ず誰かの所有物であるという関係である。
例えば「ナミ」は悪魔の実の能力を持っていない。
一方で「バラバラの実」は誰かが持っている能力である。
ゆえに、キャラクターが主で悪魔の実の能力が従となる。
また、先ほど後述するといった外部キーをどちらに書くか問題については
自身が他のテーブルをたどるキーを所持している場合は、belongs_to
自身が他のテーブルからたどるキーで示されている場合は、has_one
というルールがある。
したがって、悪魔の実の能力にch_id
を持たせている。
まとめ
正直、初め何も考えずにキャラクターを主キーにしようとしていた。(普段Userを主キーに設定されていることが多いので、、)
しかし、主キーはインデックスや更新頻度など目的を考えて設定する必要がある。
また、主キーについて、それからhas_one
とbelongs_to
についてを上手くまとめようとしていく際に、
そもそもまず何を基準にしてテーブルを分けていくのかがなかなか難しいと感じた。
データベースは初めに作成するので、ここで時間を割かないようしっかり理解しておく必要がある。
どこを主キーにしたら良いのか、主従関係はどうなっているのかというのは慣れていないと時間がかかりそうなので、今後は主キーの設定箇所や主従関係に注目しながらデータベースを見ていこうと感じた。