勉強日記

チラ裏

PoEAA ch12 Identity Field

martinfowler.com


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_linesorder_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を設定できない
    • Oracleだとdatabase counterというのがあり良い感じ
  • GUID
    • メリット
      • マシン横断的に一意
    • デメリット
      • 長い
        • 読みづらく、タイピングもしづらい
        • 【補】連番でないので、時系列情報をもたない
      • パフォーマンス問題
        • インデックスがあるとき特に
          • 【補】長い文字列はインデックスが遅い
  • 自前で生成
    • 単純な方法: read-lockしてMAX(id) + 1
    • よりよい方法: キー採番テーブルを別途用意する
      • DB一意/テーブル一意両方に対応可能
        • テーブル一意の場合は、table_nameカラムと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
    • すてきな