SQLアンチパターン-6章 ポリモーフィック関連-まとめ


複数のモデルにまたがって存在しているモデルの扱い

1対多、多対多の関係性のあるモデルについて考えます。

本(book)モデルと
コメント(comment)モデルがあったとしましょう。

  • 本に対してコメントをつけられる事ができます。
  • 本に対してコメントは複数つける事ができます。

ここで、本の執筆者である
著者(author)モデルを考えてみましょう。

  • 著者に対してコメントをつけられる事ができます。
  • 著者に対してコメントは複数つける事ができます。

このとき、コメントモデルには外部キーが2つ出現しています。
book_idauthor_id です。
この2つのキーが被ってしまう恐れがあるので
単純にテーブル結合をしてデータを取り出すことはできなくなります。

ポリモーフィック関連

上記のパターンになったときに、思いつかれる解決策があります。
それがポリモーフィック関連と言います。

単純に book_idauthor_id を扱う場合、
コメントテーブルに列をそれぞれ作成すれば良いです。
しかし、他にもコメントがつけられるようなモデルが新たに作成されたらどうなるでしょうか。
例えば本だけでなく、映画、テレビ、などなど・・・。
それぞれ movie_id や tv_id など、何かしらNULLの値が入ってしまう列を作ってしまうことになります。

それでは、コメントをつけるモデルのidと、その種類分けを定義した列、
comment_typecommented_id
を追加したらどうなるでしょうか。

ある行では

comment_type = book
commented_id = 2

また、ある行では

comment_type = author
commented_id = 3

というように、表す事ができるようになります。

デメリット

しかしポリモーフィック関連を使って設計すると
外部キーとして扱っている commented_id が、実際には外部キー宣言をせずして扱うことになってしまいます。外部キーは1つのテーブルにしか紐づける事ができないからです。
そのため、その外部キーがあるテーブルと紐づいたときに、値が存在しているのかを保証するための参照整合性制約を設ける事ができなくなります。

また、コメントテーブルのデータを取得する場合、
外部結合で複数のモデルを結合し、結合する必要があります。

ポリモーフィック関連を使うと、DBのでデータ制約を利用する事ができなくなるので
アプリケーション側で調整する必要があります。

Railsはこの問題に対応している

フレームワークによってはこの問題に対応しているものもあります。
例えばRailsでは、polymorphic属性を宣言する事で、1つのモデルを複数のモデルに紐づけて外部キーを設定する事ができます。

ポリモーフィック関連を使う場面

外部キーのように紐づけたいモデルが、複数存在し、かつ、どのようなモデルが現れうるのか、将来的に不透明であるという確度が高いときには利用せざるを得ないかもしれません。

ポリモーフィック関連の代替策

交差テーブルを作成する

最初の例を元に説明すると
books_comments テーブルと
authors_comments テーブルを作成する方法です。
交差テーブルが存在する事で、どのモデルを示すかを表していた comment_type を利用する必要が無くなります。

注意点としては、UNIQE制約を利用しないと、自然と多対多の関連づけが作成されてしまう事です。
また、両方の交差テーブルに同じ comment_idが存在しうるので、
アプリケーション側で対応する必要もあります。

共通の親テーブルを作成する

book , author, comment の全ての親となる reputation モデルを作成したとします。
book , author, comment の全てが外部キーとしてreputation_idという擬似キーを持たせる事で、コメントモデルを元に同じreputation_idに紐づいたbookauthorモデルのデータを引っ張る事が可能になります。逆も然りで、bookから同じreputation_idに紐づいたcommentデータを引っ張る事もできるようになります。
交差テーブルを作らなくても、擬似キーだけでデータの整合性制約を利用した設計をする事が可能になります。