Dependent Mapping と Embedded Value と Serialized LOB は、いずれもオブジェクトの属性が作る構造をどのようにテーブルの構造に対応付けるかに関するパターンです。
中でも Dependent Mapping は少し理解しにくいパターンですが、知ってしまえば有用なパターンです。
リレーショナルデータベースでは、id カラムのようなサロゲートキーが必要そうに見えても、必ずしもそうした全体固有キーが必要でない場合があります。カラム複数で主キーを成す、複合主キーがナチュラルキーになる場合があるからです。
ゲームに登場する武器の属性に、炎や雷といった複数の属性を付与できる仕様があるとしましょう。この関係は、もし炎や雷の属性の詳細として別のテーブルを参照する設計にした場合は、Association Table Mapping で多対多に関連付けたようなかたちになります。weapon_attribute テーブルの weapon_id と attribute_id の組み合わせは、すべての行についてユニークになります。このセットは、もし別のカラムが増えた場合でも、複合主キーとして有効です。
では、炎や雷といった属性に別テーブルに置くほどの詳細が必要なく、文字列か整数のカラムで済む場合はどうでしょうか。伝説の剣 (id=1) には炎の属性が 50%、雷の属性が 50%、職人の斧 (id=2) には水の属性が 100%、とデータ化していくと、このような表になります。
weapon_id | element | retio |
---|---|---|
1 | fire | 50 |
1 | thunder | 50 |
2 | water | 100 |
weapon_id と element の組はユニークで、ナチュラルな複合主キーにできます。「この武器へのこの属性割当だけ」という、妙な問い合わせが必要でないなら、この表にサロゲートキーは必要ありません。こんなもの、特定の武器に従属させないと意味がありませんよね。
オブジェクトへのマッピングにおいても、武器を id で特定できればよく、属性はつねに武器から辿らえるのが自然です。クラスは2種類あるけれど、物としてはそれで一体の構造になってきます。このとき、武器には Identity Field が必要ですが、属性には Identity Field が必要ありません。変更をデータベースと同期するときは、属性を個別に管理せず、属性を巻き込んだ武器全体をひとつの管理単位とします。この形になったとき、武器はエンティティとなり、属性のコレクションは Dependent Mapping で武器エンティティの一部となります。
Embedded Value は Value Object (後で出てきます) を属性に持つオブジェクトの扱いにおいて、同様にエンティティ数の節約をする方法です。
リレーショナルデータベースのデータ型には、数値、文字列、日時といった、決まったものしか準備されていません。いっぽう、Value Object はいくらでも種類を増やせるうえ、内部に持つ値も、ひとつの整数や文字列にエンコードできない場合はよくあります。このとき Foreign Key Mapping を使わずに、Value Object の内部構造をテーブルのカラムに横展開してマッピングしようとするのが Embedded Value です。
そもそも Value Object とみなしたのだから、一意性には意味がありません。エンティティと考えるのは不向きです。エンティティはクエリの対象ですが、何かの色コードの RGB 値だけを個別取得したいなんてニーズは、まずありませんね。
Serialized LOB は、より複雑な Value Object をカラムに押し込むアイデアです。
HTML DOM のような、何層あるかわからない再帰的構造を持つ Value Object は、横展開することができません。もし各要素をエンティティとするなら、別テーブルに出して頑張ってツリー構造を表現するべきですが、そうでないなら、明らかに過剰設計です。リレーショナルモデルは再帰的ツリー構造には向いていません。
そこで、JSON や XML、あるいはプログラム言語のオブジェクトシリアライズを使い、巨大なオブジェクトを文字列やバイト列にエンコードたものを、文字数の上限がないテキストカラム、あるいは LOB/BLOB と言われるデータ列用の単一カラムに詰め込むのが、Serialized LOB パターンです。
Serialized LOB を使えば何でもマッピングできると思うかもしれませんが、これはデータベース技術の都合上、アンチパターンとされています。安易にこうしたエンコードによる押し込みをすると、データにインデックスを付けることも、リレーショナルデータベースが得意なテーブルの連結もできなくなるからです。また、必ずデータを復元できる保証もありません。デシリアライズしたとき、マッピング対象のクラス詳細が、保存時とは異なっていることもあります。復元時の完全性などなくてもいいから、ただ保存できさえすればいいのだ、と言い切れる場合にのみ、有効なパターンです。