PoEAA ch12 Identity Field

PoEAAデザインパターン勉強メモ

出典: 


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

    • メリット

      • マシン横断的に一意

        • 【補】複数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

    • すてきな