Identity Field
Saves a database ID field in an object to maintain identity between an in-memory object and a database row.
-
RDBにおいてはキーで行を区別・特定する
-
とりわけPK
- 【補】リレーショナルモデルでは「候補キー」(RK)
-
-
メモリ上のオブジェクトには不要
-
DBからの読み出し・オブジェクトの構築までは問題なし
- 参照やメモリアドレスで特定できる
-
DBに書き戻すとき必要
- メモリ上のオブジェクトとRDB上の行を紐付ける必要がある
-
-
実装内容は退屈この上ない
- オブジェクトのフィールドにPKを格納するだけ
- が、考えることは結構ある
How It Works
Choosing Your Key
-
ナチュラルキー/サロゲートキー
- 【補】文中では「meaningful / meaningless keys」
- ナチュラルキーは、理論上は良いキーだが、実用上はそうでもない
-
問題点
- 一意性・不変性が崩れることがある
-
例: 社会保障番号の入力ミス
- 入力ミスされた時点で一意性が崩れる
- 修正すると不変性が崩れる
- 小さいシステムや、非常に安定したケースでは問題とならないこともある
- が、通常はサロゲートキーを選ぶだろう
-
単純キー/複合キー
-
複合キーのメリット
- あるテーブルが別のテーブルのコンテキスト下で意味をもつとき、扱いやすい
-
例: ordersとorder_lines
order_lines
はorder_id
と枝番を主キーにもつ
-
単純キーのメリット
-
全てのキーを一様に扱える
- Layer Supertypeに処理を共通化できる
-
-
複合キーは多少なりとも「意味を持つ」ことに留意する
- 【補】ナチュラルキーと同様の問題をはらむということ
-
-
テーブル一意/DB一意
- ふつうはテーブル一意で良い
-
DB一意キーの利点
-
単一のIdentity Mapで全オブジェクトを管理できる
- 個々のテーブルのIDが衝突しないため
-
-
ID枯渇問題
- 64ビット整数ならまず起こらない
-
Table Inheritance系パターンとの兼ね合い
- Class Table Inheritance、Concrete Table Inheritanceの場合は、テーブルごとに一意ではなく、継承ツリーに対して一意なキーがあると都合が良い
-
キーのサイズとパフォーマンス
-
何か決定を固める前に、まずおおよその調査を
- 【補】推測するな計測せよ
-
Representing the Identity Field in an Object
- 単純キーを同じ型のフィールドに持つのが一番単純でうまくいく
-
複合キーの場合は問題が出てくる
- 複合キーをまとめるクラスを作るのが良い
-
汎用 vs 明示的に別々のクラスにする
-
著者は普段なら「明示的」を好むが、この場合は悩ましい
- 何もしない小さなクラスが大量にできてしまう
- メリットは「複合キーの格納順を間違えない」ことだが、そもそも問題になることがあまりない
-
-
DBをまたいでデータを読み込む時のキー衝突
- 区別して保持する
Getting a New Key
-
INSERT時のキー採番
- DBの自動生成
- GUID
- 自前で生成
-
DBの自動生成
-
メリット
- 最も簡単
-
デメリット
-
親子オブジェクトを一度に登録できない
-
例: OrderとOrderLine
- OrderオブジェクトをINSERTしない限り
orders.id
は採番されない orders.id
が採番されないとorder_lines.order_id
を設定できない
- OrderオブジェクトをINSERTしない限り
-
-
- Oracleだとdatabase counterというのがあり良い感じ
-
-
GUID
-
メリット
-
マシン横断的に一意
- 【補】複数DBをまたいだりクラスタリングしたりしても衝突しない
-
-
デメリット
-
長い
- 読みづらく、タイピングもしづらい
- 【補】連番でないので、時系列情報をもたない
-
パフォーマンス問題
-
インデックスがあるとき特に
- 【補】長い文字列はインデックスが遅い
-
-
-
-
自前で生成
-
単純な方法: read-lockして
MAX(id) + 1
- デメリット: システムの並列性を損なう
- トランザクション分離レベルが低いと、複数のトランザクションに同一のIDを配ってしまうことに注意
-
よりよい方法: キー採番テーブルを別途用意する
-
DB一意/テーブル一意両方に対応可能
- テーブル一意の場合は、
table_name
カラムとid
カラムを持つ感じ
- テーブル一意の場合は、
-
-
-
キー採番テーブルを用意する場合は、独立したトランザクションで採番を行うとよい
- アクセス競合低減
-
欠点: レコードデータ(Ordersとか)の更新をロールバックした場合、IDに欠番を生じる
- 【補】レコードデータと別のトランザクションなので、こちらはロールバックされない
- そんなに問題になることもない
-
キー採番テーブルを用意する場合は、採番処理をクラスに切り出すとよい
-
Service Stubを適用しやすくなる
- テストのため
-
When to Use It
-
メモリ上のオブジェクトとRDB上の行を紐付ける必要があるとき
-
例
- Domain Model
- Row Data Gateway
- 【補】Active Record
-
-
対応するテーブルを持たず、「値が等価なら同一」な小さなオブジェクトにはEmbedded Valueを適用せよ
- 【補】Value Objectの一種
-
例
- お金(金額 + 通貨)
- 日付範囲(begin + end)
-
複雑なグラフで、かつSQLによる問い合わせが必要ないものはSerialized LOB
- 実装が簡単でパフォーマンスも優れる
- 【補】今日びはjsonカラム等のベンダ拡張があり、SQLで問い合わせできたりする
-
Identity Fieldを持つ代わりに、Identity Mapを拡張するという道
-
Identity Mapにルックアップ機能をもたせる
- オブジェクト => キー
- キー => オブジェクト
- オブジェクトにIdentity Fieldをもたせるほうが楽なので、あまり見ることはない
-
英語
-
mind-numbingly
- 極めて退屈でつまらない
-
oodles
- 極めてどっさり
-
rare
- すてきな